- Implement 2.0 image key feature.
[mono.git] / mcs / class / Managed.Windows.Forms / System.Windows.Forms / FileDialog.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) 2006 Alexander Olk
21 //
22 // Authors:
23 //
24 //  Alexander Olk       alex.olk@googlemail.com
25 //  Gert Driesen (drieseng@users.sourceforge.net)
26 //
27 // TODO:
28 // Keyboard shortcuts (DEL, F5, F2)
29 // ??
30
31 using System;
32 using System.Collections;
33 using System.Collections.Specialized;
34 using System.ComponentModel;
35 using System.Drawing;
36 using System.IO;
37 using System.Resources;
38 using System.Threading;
39 using System.Xml;
40
41 namespace System.Windows.Forms
42 {
43         #region FileDialog
44         [DefaultProperty ("FileName")]
45         [DefaultEvent ("FileOk")]
46         public abstract class FileDialog : CommonDialog
47         {
48                 protected static readonly object EventFileOk = new object ();
49                 private static int MaxFileNameItems = 10;
50                 
51                 internal enum FileDialogType
52                 {
53                         OpenFileDialog,
54                         SaveFileDialog
55                 }
56                 
57                 private bool addExtension = true;
58                 private bool checkFileExists;
59                 private bool checkPathExists = true;
60                 private string defaultExt;
61                 private bool dereferenceLinks = true;
62                 private string[] fileNames;
63                 private string filter = "";
64                 private int filterIndex = 1;
65                 private int setFilterIndex = 1;
66                 private string initialDirectory;
67                 private bool restoreDirectory;
68                 private bool showHelp;
69                 private string title;
70                 private bool validateNames = true;
71 #if NET_2_0
72                 private bool checkForIllegalChars = true;
73 #endif
74                 
75                 private Button cancelButton;
76                 private ToolBarButton upToolBarButton;
77                 private PopupButtonPanel popupButtonPanel;
78                 private Button openSaveButton;
79                 private Button helpButton;
80                 private Label fileTypeLabel;
81                 private ToolBarButton menueToolBarButton;
82                 private ContextMenu menueToolBarButtonContextMenu;
83                 private ToolBar smallButtonToolBar;
84                 private DirComboBox dirComboBox;
85                 private ComboBox fileNameComboBox;
86                 private Label fileNameLabel;
87                 private MWFFileView mwfFileView;
88                 private Label searchSaveLabel;
89                 private ToolBarButton newdirToolBarButton;
90                 private ToolBarButton backToolBarButton;
91                 private ComboBox fileTypeComboBox;
92                 private ImageList imageListTopToolbar;
93                 private CheckBox readonlyCheckBox;
94                 
95                 private bool multiSelect;
96                 
97                 private string restoreDirectoryString = String.Empty;
98                 
99                 internal FileDialogType fileDialogType;
100                 
101                 private bool do_not_call_OnSelectedIndexChangedFileTypeComboBox;
102                 
103                 private bool showReadOnly;
104                 private bool readOnlyChecked;
105                 internal bool createPrompt;
106                 internal bool overwritePrompt = true;
107                 
108                 internal FileFilter fileFilter;
109                 
110                 private string lastFolder = String.Empty;
111                 
112                 private MWFVFS vfs;
113                 
114                 private readonly string filedialog_string = "FileDialog";
115                 private readonly string lastfolder_string = "LastFolder";
116                 private readonly string width_string = "Width";
117                 private readonly string height_string = "Height";
118                 private readonly string filenames_string = "FileNames";
119                 private readonly string x_string = "X";
120                 private readonly string y_string = "Y";
121                 
122                 private bool disable_form_closed_event = false;
123                 
124                 internal FileDialog ()
125                 {
126                         vfs = new MWFVFS ();
127                         
128                         Size formConfigSize = Size.Empty;
129                         Point formConfigLocation = Point.Empty;
130                         string[] configFileNames = null;
131                         
132                         object formWidth = MWFConfig.GetValue (filedialog_string, width_string);
133                         
134                         object formHeight = MWFConfig.GetValue (filedialog_string, height_string);
135                         
136                         if (formHeight != null && formWidth != null)
137                                 formConfigSize = new Size ((int)formWidth, (int)formHeight);
138                         
139                         object formLocationX = MWFConfig.GetValue (filedialog_string, x_string);
140                         object formLocationY = MWFConfig.GetValue (filedialog_string, y_string);
141                         
142                         if (formLocationX != null && formLocationY != null)
143                                 formConfigLocation = new Point ((int)formLocationX, (int)formLocationY);
144                         
145                         configFileNames = (string[])MWFConfig.GetValue (filedialog_string, filenames_string);
146                         
147                         fileTypeComboBox = new ComboBox ();
148                         backToolBarButton = new ToolBarButton ();
149                         newdirToolBarButton = new ToolBarButton ();
150                         searchSaveLabel = new Label ();
151                         mwfFileView = new MWFFileView (vfs);
152                         fileNameLabel = new Label ();
153                         fileNameComboBox = new ComboBox ();
154                         dirComboBox = new DirComboBox (vfs);
155                         smallButtonToolBar = new ToolBar ();
156                         menueToolBarButton = new ToolBarButton ();
157                         fileTypeLabel = new Label ();
158                         openSaveButton = new Button ();
159                         form.AcceptButton = openSaveButton;
160                         helpButton = new Button ();
161                         popupButtonPanel = new PopupButtonPanel ();
162                         upToolBarButton = new ToolBarButton ();
163                         cancelButton = new Button ();
164                         form.CancelButton = cancelButton;
165                         imageListTopToolbar = new ImageList ();
166                         menueToolBarButtonContextMenu = new ContextMenu ();
167                         readonlyCheckBox = new CheckBox ();
168                         
169                         form.SuspendLayout ();
170                         
171                         //imageListTopToolbar
172                         imageListTopToolbar.ColorDepth = ColorDepth.Depth32Bit;
173                         imageListTopToolbar.ImageSize = new Size (16, 16); // 16, 16
174                         imageListTopToolbar.Images.Add (ResourceImageLoader.Get ("go-previous.png"));
175                         imageListTopToolbar.Images.Add (ResourceImageLoader.Get ("go-top.png"));
176                         imageListTopToolbar.Images.Add (ResourceImageLoader.Get ("folder-new.png"));
177                         imageListTopToolbar.Images.Add (ResourceImageLoader.Get ("preferences-system-windows.png"));
178                         imageListTopToolbar.TransparentColor = Color.Transparent;
179                         
180                         // searchLabel
181                         searchSaveLabel.FlatStyle = FlatStyle.System;
182                         searchSaveLabel.Location = new Point (7, 8);
183                         searchSaveLabel.Size = new Size (72, 21);
184                         searchSaveLabel.TextAlign = ContentAlignment.MiddleRight;
185                         
186                         // dirComboBox
187                         dirComboBox.Anchor = ((AnchorStyles)(((AnchorStyles.Top | AnchorStyles.Left) | AnchorStyles.Right)));
188                         dirComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
189                         dirComboBox.Location = new Point (99, 8);
190                         dirComboBox.Size = new Size (260, 21);
191                         dirComboBox.TabIndex = 7;
192                         
193                         // smallButtonToolBar
194                         smallButtonToolBar.Anchor = ((AnchorStyles)((AnchorStyles.Top | AnchorStyles.Right)));
195                         smallButtonToolBar.Appearance = ToolBarAppearance.Flat;
196                         smallButtonToolBar.AutoSize = false;
197                         smallButtonToolBar.Buttons.AddRange (new ToolBarButton [] {
198                                                                      backToolBarButton,
199                                                                      upToolBarButton,
200                                                                      newdirToolBarButton,
201                                                                      menueToolBarButton});
202                         smallButtonToolBar.ButtonSize = new Size (24, 24); // 21, 16
203                         smallButtonToolBar.Divider = false;
204                         smallButtonToolBar.Dock = DockStyle.None;
205                         smallButtonToolBar.DropDownArrows = true;
206                         smallButtonToolBar.ImageList = imageListTopToolbar;
207                         smallButtonToolBar.Location = new Point (372, 6);
208                         smallButtonToolBar.ShowToolTips = true;
209                         smallButtonToolBar.Size = new Size (140, 28);
210                         smallButtonToolBar.TabIndex = 8;
211                         smallButtonToolBar.TextAlign = ToolBarTextAlign.Right;
212                         
213                         // buttonPanel
214                         popupButtonPanel.Dock = DockStyle.None;
215                         popupButtonPanel.Location = new Point (7, 37);
216                         popupButtonPanel.TabIndex = 9;
217                         
218                         // mwfFileView
219                         mwfFileView.Anchor = ((AnchorStyles)((((AnchorStyles.Top | AnchorStyles.Bottom) | AnchorStyles.Left) | AnchorStyles.Right)));
220                         mwfFileView.Location = new Point (99, 37);
221                         mwfFileView.Size = new Size (449, 282);
222                         mwfFileView.Columns.Add (" Name", 170, HorizontalAlignment.Left);
223                         mwfFileView.Columns.Add ("Size ", 80, HorizontalAlignment.Right);
224                         mwfFileView.Columns.Add (" Type", 100, HorizontalAlignment.Left);
225                         mwfFileView.Columns.Add (" Last Access", 150, HorizontalAlignment.Left);
226                         mwfFileView.AllowColumnReorder = true;
227                         mwfFileView.MultiSelect = false;
228                         mwfFileView.TabIndex = 10;
229                         mwfFileView.RegisterSender (dirComboBox);
230                         mwfFileView.RegisterSender (popupButtonPanel);
231                         
232                         // fileNameLabel
233                         fileNameLabel.Anchor = ((AnchorStyles)((AnchorStyles.Bottom | AnchorStyles.Left)));
234                         fileNameLabel.FlatStyle = FlatStyle.System;
235                         fileNameLabel.Location = new Point (102, 330);
236                         fileNameLabel.Size = new Size (70, 21);
237                         fileNameLabel.Text = "File name:";
238                         fileNameLabel.TextAlign = ContentAlignment.MiddleLeft;
239                         
240                         // fileNameComboBox
241                         fileNameComboBox.Anchor = ((AnchorStyles)(((AnchorStyles.Bottom | AnchorStyles.Left) | AnchorStyles.Right)));
242                         fileNameComboBox.Location = new Point (195, 330);
243                         fileNameComboBox.Size = new Size (245, 21);
244                         fileNameComboBox.TabIndex = 1;
245                         fileNameComboBox.MaxDropDownItems = MaxFileNameItems;
246                         
247                         if (configFileNames != null) {
248                                 foreach (string configFileName in configFileNames) {
249                                         if (configFileName == null || configFileName.Trim ().Length == 0)
250                                                 continue;
251                                         // add no more than 10 items
252                                         if (fileNameComboBox.Items.Count >= MaxFileNameItems)
253                                                 break;
254                                         fileNameComboBox.Items.Add (configFileName);
255                                 }
256                         }
257                         
258                         // fileTypeLabel
259                         fileTypeLabel.Anchor = ((AnchorStyles)((AnchorStyles.Bottom | AnchorStyles.Left)));
260                         fileTypeLabel.FlatStyle = FlatStyle.System;
261                         fileTypeLabel.Location = new Point (102, 356);
262                         fileTypeLabel.Size = new Size (90, 21);
263                         fileTypeLabel.Text = "Files of type:";
264                         fileTypeLabel.TextAlign = ContentAlignment.MiddleLeft;
265                         
266                         // fileTypeComboBox
267                         fileTypeComboBox.Anchor = ((AnchorStyles)(((AnchorStyles.Bottom | AnchorStyles.Left) | AnchorStyles.Right)));
268                         fileTypeComboBox.DropDownStyle = ComboBoxStyle.DropDownList;
269                         fileTypeComboBox.Location = new Point (195, 356);
270                         fileTypeComboBox.Size = new Size (245, 21);
271                         fileTypeComboBox.TabIndex = 2;
272                         
273                         // backToolBarButton
274                         backToolBarButton.ImageIndex = 0;
275                         backToolBarButton.Enabled = false;
276                         backToolBarButton.Style = ToolBarButtonStyle.PushButton;
277                         mwfFileView.AddControlToEnableDisableByDirStack (backToolBarButton);
278                         
279                         // upToolBarButton
280                         upToolBarButton.ImageIndex = 1;
281                         upToolBarButton.Style = ToolBarButtonStyle.PushButton;
282                         mwfFileView.SetFolderUpToolBarButton (upToolBarButton);
283                         
284                         // newdirToolBarButton
285                         newdirToolBarButton.ImageIndex = 2;
286                         newdirToolBarButton.Style = ToolBarButtonStyle.PushButton;
287                         
288                         // menueToolBarButton
289                         menueToolBarButton.ImageIndex = 3;
290                         menueToolBarButton.DropDownMenu = menueToolBarButtonContextMenu;
291                         menueToolBarButton.Style = ToolBarButtonStyle.DropDownButton;
292                         
293                         // menueToolBarButtonContextMenu
294                         menueToolBarButtonContextMenu.MenuItems.AddRange (mwfFileView.ViewMenuItems);
295                         
296                         // openSaveButton
297                         openSaveButton.Anchor = ((AnchorStyles)((AnchorStyles.Bottom | AnchorStyles.Right)));
298                         openSaveButton.FlatStyle = FlatStyle.System;
299                         openSaveButton.Location = new Point (475, 330);
300                         openSaveButton.Size = new Size (72, 21);
301                         openSaveButton.TabIndex = 4;
302                         openSaveButton.FlatStyle = FlatStyle.System;
303                         
304                         // cancelButton
305                         cancelButton.Anchor = ((AnchorStyles)((AnchorStyles.Bottom | AnchorStyles.Right)));
306                         cancelButton.FlatStyle = FlatStyle.System;
307                         cancelButton.Location = new Point (475, 356);
308                         cancelButton.Size = new Size (72, 21);
309                         cancelButton.TabIndex = 5;
310                         cancelButton.Text = "Cancel";
311                         cancelButton.FlatStyle = FlatStyle.System;
312                         
313                         // helpButton
314                         helpButton.Anchor = ((AnchorStyles)((AnchorStyles.Bottom | AnchorStyles.Right)));
315                         helpButton.FlatStyle = FlatStyle.System;
316                         helpButton.Location = new Point (475, 350);
317                         helpButton.Size = new Size (72, 21);
318                         helpButton.TabIndex = 6;
319                         helpButton.Text = "Help";
320                         helpButton.FlatStyle = FlatStyle.System;
321                         
322                         // checkBox
323                         readonlyCheckBox.Anchor = ((AnchorStyles)(((AnchorStyles.Bottom | AnchorStyles.Left) | AnchorStyles.Right)));
324                         readonlyCheckBox.Text = "Open Readonly";
325                         readonlyCheckBox.Location = new Point (195, 350);
326                         readonlyCheckBox.Size = new Size (245, 21);
327                         readonlyCheckBox.TabIndex = 3;
328                         readonlyCheckBox.FlatStyle = FlatStyle.System;
329                         
330                         form.SizeGripStyle = SizeGripStyle.Show;
331                         
332                         form.MaximizeBox = true;
333                         form.MinimizeBox = true;
334                         form.FormBorderStyle = FormBorderStyle.Sizable;
335                         form.MinimumSize = new Size (554, 405);
336                         
337                         form.ClientSize =  new Size (554, 405); // 384
338                         
339                         form.Controls.Add (smallButtonToolBar);
340                         form.Controls.Add (cancelButton);
341                         form.Controls.Add (openSaveButton);
342                         form.Controls.Add (mwfFileView);
343                         form.Controls.Add (fileTypeLabel);
344                         form.Controls.Add (fileNameLabel);
345                         form.Controls.Add (fileTypeComboBox);
346                         form.Controls.Add (fileNameComboBox);
347                         form.Controls.Add (dirComboBox);
348                         form.Controls.Add (searchSaveLabel);
349                         form.Controls.Add (popupButtonPanel);
350                         
351                         form.ResumeLayout (false);
352                         
353                         if (formConfigSize != Size.Empty) {
354                                 form.Size = formConfigSize;
355                         }
356                         
357                         if (formConfigLocation != Point.Empty) {
358                                 form.Location = formConfigLocation;
359                         }
360                         
361                         openSaveButton.Click += new EventHandler (OnClickOpenSaveButton);
362                         cancelButton.Click += new EventHandler (OnClickCancelButton);
363                         helpButton.Click += new EventHandler (OnClickHelpButton);
364                         
365                         smallButtonToolBar.ButtonClick += new ToolBarButtonClickEventHandler (OnClickSmallButtonToolBar);
366                         
367                         fileTypeComboBox.SelectedIndexChanged += new EventHandler (OnSelectedIndexChangedFileTypeComboBox);
368                         
369                         mwfFileView.SelectedFileChanged += new EventHandler (OnSelectedFileChangedFileView);
370                         mwfFileView.ForceDialogEnd += new EventHandler (OnForceDialogEndFileView);
371                         mwfFileView.SelectedFilesChanged += new EventHandler (OnSelectedFilesChangedFileView);
372                         
373                         dirComboBox.DirectoryChanged += new EventHandler (OnDirectoryChangedDirComboBox);
374                         popupButtonPanel.DirectoryChanged += new EventHandler (OnDirectoryChangedPopupButtonPanel);
375                         
376                         readonlyCheckBox.CheckedChanged += new EventHandler (OnCheckCheckChanged);
377 #if NET_2_0
378                         form.FormClosed += new FormClosedEventHandler (OnFileDialogFormClosed);
379 #else
380                         form.Closed += new EventHandler (OnFileDialogFormClosed);
381 #endif
382                 }
383                 
384                 [DefaultValue(true)]
385                 public bool AddExtension {
386                         get {
387                                 return addExtension;
388                         }
389                         
390                         set {
391                                 addExtension = value;
392                         }
393                 }
394                 
395                 [DefaultValue(false)]
396                 public virtual bool CheckFileExists {
397                         get {
398                                 return checkFileExists;
399                         }
400                         
401                         set {
402                                 checkFileExists = value;
403                         }
404                 }
405                 
406                 [DefaultValue(true)]
407                 public bool CheckPathExists {
408                         get {
409                                 return checkPathExists;
410                         }
411                         
412                         set {
413                                 checkPathExists = value;
414                         }
415                 }
416                 
417                 [DefaultValue("")]
418                 public string DefaultExt {
419                         get {
420                                 if (defaultExt == null)
421                                         return string.Empty;
422                                 return defaultExt;
423                         }
424                         set {
425                                 if (value != null && value.Length > 0) {
426                                         // remove leading dot
427                                         if (value [0] == '.')
428                                                 value = value.Substring (1);
429                                 }
430                                 defaultExt = value;
431                         }
432                 }
433                 
434                 // in MS.NET it doesn't make a difference if
435                 // DerefenceLinks is true or false
436                 // if the selected file is a link FileDialog
437                 // always returns the link
438                 [DefaultValue(true)]
439                 public bool DereferenceLinks {
440                         get {
441                                 return dereferenceLinks;
442                         }
443                         
444                         set {
445                                 dereferenceLinks = value;
446                         }
447                 }
448                 
449                 [DefaultValue("")]
450                 public string FileName {
451                         get {
452                                 if (fileNames == null || fileNames.Length == 0)
453                                         return string.Empty;
454
455                                 if (fileNames [0].Length == 0)
456                                         return string.Empty;
457
458 #if NET_2_0
459                                 // skip check for illegal characters if the filename was set
460                                 // through FileDialog API
461                                 if (!checkForIllegalChars)
462                                         return fileNames [0];
463 #endif
464
465                                 // ensure filename contains only valid characters
466                                 Path.GetFullPath (fileNames [0]);
467                                 // but return filename as is
468                                 return fileNames [0];
469
470                         }
471                         
472                         set {
473                                 if (value != null) {
474                                         fileNames = new string [1] { value };
475                                 } else {
476                                         fileNames = new string [0];
477                                 }
478
479 #if NET_2_0
480                                 // skip check for illegal characters if the filename was set
481                                 // through FileDialog API
482                                 checkForIllegalChars = false;
483 #endif
484                         }
485                 }
486                 
487                 [Browsable(false)]
488                 [DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
489                 public string[] FileNames {
490                         get {
491                                 if (fileNames == null || fileNames.Length == 0) {
492                                         return new string [0];
493                                 }
494                                 
495                                 string[] new_filenames = new string [fileNames.Length];
496                                 fileNames.CopyTo (new_filenames, 0);
497
498 #if NET_2_0
499                                 // skip check for illegal characters if the filename was set
500                                 // through FileDialog API
501                                 if (!checkForIllegalChars)
502                                         return new_filenames;
503 #endif
504
505                                 foreach (string fileName in new_filenames) {
506                                         // ensure filename contains only valid characters
507                                         Path.GetFullPath (fileName);
508                                 }
509                                 return new_filenames;
510                         }
511                 }
512                 
513                 [DefaultValue("")]
514                 [Localizable(true)]
515                 public string Filter {
516                         get {
517                                 return filter;
518                         }
519                         
520                         set {
521                                 if (value == null) {
522                                         filter = "";
523                                         if (fileFilter != null)
524                                                 fileFilter.FilterArrayList.Clear ();
525                                 } else {
526                                         if (FileFilter.CheckFilter (value)) {
527                                                 filter = value;
528                                                 
529                                                 fileFilter = new FileFilter (filter);
530                                         } else
531                                                 throw new ArgumentException ("The provided filter string"
532                                                         + " is invalid. The filter string should contain a"
533                                                         + " description of the filter, followed by the "
534                                                         + " vertical bar (|) and the filter pattern. The"
535                                                         + " strings for different filtering options should"
536                                                         + " also be separated by the vertical bar. Example:"
537                                                         + " Text files (*.txt)|*.txt|All files (*.*)|*.*");
538                                 }
539                                 
540                                 UpdateFilters ();
541                         }
542                 }
543                 
544                 [DefaultValue(1)]
545                 public int FilterIndex {
546                         get {
547                                 return setFilterIndex;
548                         }
549                         
550                         set {
551                                 setFilterIndex = value;
552                                 
553                                 if (value < 1)
554                                         filterIndex = 1;
555                                 else
556                                         filterIndex = value;
557                                 
558                                 SelectFilter ();
559                         }
560                 }
561                 
562                 [DefaultValue("")]
563                 public string InitialDirectory {
564                         get {
565                                 if (initialDirectory == null)
566                                         return string.Empty;
567                                 return initialDirectory;
568                         }
569                         set {
570                                 initialDirectory = value;
571                         }
572                 }
573                 
574                 [DefaultValue(false)]
575                 public bool RestoreDirectory {
576                         get {
577                                 return restoreDirectory;
578                         }
579                         
580                         set {
581                                 restoreDirectory = value;
582                         }
583                 }
584                 
585                 [DefaultValue(false)]
586                 public bool ShowHelp {
587                         get {
588                                 return showHelp;
589                         }
590                         
591                         set {
592                                 showHelp = value;
593                                 ResizeAndRelocateForHelpOrReadOnly ();
594                         }
595                 }
596                 
597                 [DefaultValue("")]
598                 [Localizable(true)]
599                 public string Title {
600                         get {
601                                 if (title == null)
602                                         return string.Empty;
603                                 return title;
604                         }
605                         set {
606                                 title = value;
607                         }
608                 }
609                 
610                 // this one is a hard one ;)
611                 // Win32 filename:
612                 // - up to MAX_PATH characters (windef.h) = 260
613                 // - no trailing dots or spaces
614                 // - case preserving
615                 // - etc...
616                 // NTFS/Posix filename:
617                 // - up to 32,768 Unicode characters
618                 // - trailing periods or spaces
619                 // - case sensitive
620                 // - etc...
621                 [DefaultValue(true)]
622                 public bool ValidateNames {
623                         get {
624                                 return validateNames;
625                         }
626                         
627                         set {
628                                 validateNames = value;
629                         }
630                 }
631                 
632                 public override void Reset ()
633                 {
634                         addExtension = true;
635                         checkFileExists = false;
636                         checkPathExists = true;
637                         DefaultExt = null;
638                         dereferenceLinks = true;
639                         FileName = null;
640                         Filter = String.Empty;
641                         FilterIndex = 1;
642                         InitialDirectory = null;
643                         restoreDirectory = false;
644                         ShowHelp = false;
645                         Title = null;
646                         validateNames = true;
647                         
648                         UpdateFilters ();
649                 }
650                 
651                 public override string ToString ()
652                 {
653                         return String.Format("{0}: Title: {1}, FileName: {2}", base.ToString (), Title, FileName);
654                 }
655                 
656                 public event CancelEventHandler FileOk {
657                         add { Events.AddHandler (EventFileOk, value); }
658                         remove { Events.RemoveHandler (EventFileOk, value); }
659                 }
660                 
661                 protected virtual IntPtr Instance {
662                         get {
663                                 if (form == null)
664                                         return IntPtr.Zero;
665                                 return form.Handle;
666                         }
667                 }
668                 
669                 // This is just for internal use with MSs version, so it doesn't need to be implemented
670                 // as it can't really be accessed anyways
671                 protected int Options {
672                         get { return -1; }
673                 }
674
675                 internal virtual string DialogTitle {
676                         get {
677                                 return Title;
678                         }
679                 }
680                 
681                 [MonoTODO]
682                 protected  override IntPtr HookProc (IntPtr hWnd, int msg, IntPtr wparam, IntPtr lparam)
683                 {
684                         throw new NotImplementedException ();
685                 }
686                 
687                 protected void OnFileOk (CancelEventArgs e)
688                 {
689                         WriteConfigValues (e);
690                         
691                         CancelEventHandler fo = (CancelEventHandler) Events [EventFileOk];
692                         if (fo != null)
693                                 fo (this, e);
694                         
695                         Mime.CleanFileCache ();
696                         
697                         disable_form_closed_event = true;
698                 }
699                 
700                 protected override bool RunDialog (IntPtr hWndOwner)
701                 {
702                         ReadConfigValues ();
703                         form.Text = DialogTitle;
704
705                         // avoid using the FileNames property to skip the invalid characters
706                         // check
707                         string fileName = null;
708                         if (fileNames != null && fileNames.Length != 0)
709                                 fileName = fileNames [0];
710                         else
711                                 fileName = string.Empty;
712
713                         form.Refresh ();
714
715                         SetFileAndDirectory (fileName);
716                         fileNameComboBox.Select ();
717                         
718                         return true;
719                 }
720                 
721                 internal virtual bool ShowReadOnly {
722                         set {
723                                 showReadOnly = value;
724                                 ResizeAndRelocateForHelpOrReadOnly ();
725                         }
726                         
727                         get {
728                                 return showReadOnly;
729                         }
730                 }
731                 
732                 internal virtual bool ReadOnlyChecked {
733                         set {
734                                 readOnlyChecked = value;
735                                 readonlyCheckBox.Checked = value;
736                         }
737                         
738                         get {
739                                 return readOnlyChecked;
740                         }
741                 }
742                 
743                 internal bool BMultiSelect {
744                         set {
745                                 multiSelect = value;
746                                 mwfFileView.MultiSelect = value;
747                         }
748                         
749                         get {
750                                 return multiSelect;
751                         }
752                 }
753                 
754                 internal string OpenSaveButtonText {
755                         set {
756                                 openSaveButton.Text = value;
757                         }
758                 }
759                 
760                 internal string SearchSaveLabel {
761                         set {
762                                 searchSaveLabel.Text = value;
763                         }
764                 }
765
766                 internal string FileTypeLabel {
767                         set {
768                                 fileTypeLabel.Text = value;
769                         }
770                 }
771
772                 private void SelectFilter ()
773                 {
774                         if (mwfFileView.FilterArrayList == null || filterIndex > mwfFileView.FilterArrayList.Count)
775                                 return;
776                         
777                         do_not_call_OnSelectedIndexChangedFileTypeComboBox = true;
778                         fileTypeComboBox.BeginUpdate ();
779                         fileTypeComboBox.SelectedIndex = filterIndex - 1;
780                         fileTypeComboBox.EndUpdate ();
781                         do_not_call_OnSelectedIndexChangedFileTypeComboBox = false;
782                         mwfFileView.FilterIndex = filterIndex;
783                 }
784
785                 private void SetFileAndDirectory (string fname)
786                 {
787                         if (fname.Length != 0) {
788                                 bool rooted = Path.IsPathRooted (fname);
789                                 if (!rooted) {
790                                         mwfFileView.ChangeDirectory (null, lastFolder);
791                                         fileNameComboBox.Text = fname;
792                                 } else {
793                                         string dirname = Path.GetDirectoryName (fname);
794                                         if (dirname != null && dirname.Length > 0 && Directory.Exists (dirname)) {
795                                                 fileNameComboBox.Text = Path.GetFileName (fname);
796                                                 mwfFileView.ChangeDirectory (null, dirname);
797                                         } else {
798                                                 fileNameComboBox.Text = fname;
799                                                 mwfFileView.ChangeDirectory (null, lastFolder);
800                                         }
801                                 }
802                         } else {
803                                 mwfFileView.ChangeDirectory (null, lastFolder);
804                                 fileNameComboBox.Text = null;
805                         }
806                 }
807                 
808                 void OnClickOpenSaveButton (object sender, EventArgs e)
809                 {
810 #if NET_2_0
811                         // for filenames typed or selected by user, enable check for 
812                         // illegal characters in filename(s)
813                         checkForIllegalChars = true;
814 #endif
815
816                         if (fileDialogType == FileDialogType.OpenFileDialog) {
817                                 ListView.SelectedListViewItemCollection sl = mwfFileView.SelectedItems;
818                                 if (sl.Count > 0 && sl [0] != null) {
819                                         if (sl.Count == 1) {
820                                                 FileViewListViewItem item = sl [0] as FileViewListViewItem;
821                                                 FSEntry fsEntry = item.FSEntry;
822                                                 
823                                                 if (fsEntry.Attributes == FileAttributes.Directory) {
824                                                         mwfFileView.ChangeDirectory (null, fsEntry.FullName);
825                                                         return;
826                                                 }
827                                         } else {
828                                                 foreach (FileViewListViewItem item in sl) {
829                                                         FSEntry fsEntry = item.FSEntry;
830                                                         if (fsEntry.Attributes == FileAttributes.Directory) {
831                                                                 mwfFileView.ChangeDirectory (null, fsEntry.FullName);
832                                                                 return;
833                                                         }
834                                                 }
835                                         }
836                                 }
837                         }
838                         
839                         string internalfullfilename = String.Empty;
840                         
841                         if (!multiSelect) {
842                                 string fileFromComboBox = fileNameComboBox.Text.Trim ();
843                                 
844                                 if (fileFromComboBox.Length > 0) {
845                                         if (!Path.IsPathRooted (fileFromComboBox)) {
846                                                 // on unix currentRealFolder for "Recently used files" is null,
847                                                 // because recently used files don't get saved as links in a directory
848                                                 // recently used files get saved in a xml file
849                                                 if (mwfFileView.CurrentRealFolder != null)
850                                                         fileFromComboBox = Path.Combine (mwfFileView.CurrentRealFolder, fileFromComboBox);
851                                                 else
852                                                 if (mwfFileView.CurrentFSEntry != null) {
853                                                         fileFromComboBox = mwfFileView.CurrentFSEntry.FullName;
854                                                 }
855                                         }
856                                         
857                                         FileInfo fileInfo = new FileInfo (fileFromComboBox);
858                                         
859                                         if (fileInfo.Exists || fileDialogType == FileDialogType.SaveFileDialog) {
860                                                 internalfullfilename = fileFromComboBox;
861                                         } else {
862                                                 DirectoryInfo dirInfo = new DirectoryInfo (fileFromComboBox);
863                                                 if (dirInfo.Exists) {
864                                                         mwfFileView.ChangeDirectory (null, dirInfo.FullName);
865                                                         fileNameComboBox.Text = null;
866                                                         return;
867                                                 } else {
868                                                         internalfullfilename = fileFromComboBox;
869                                                 }
870                                         }
871                                 } else
872                                         return;
873                                 
874                                 if (fileDialogType == FileDialogType.OpenFileDialog) {
875                                         if (checkFileExists) {
876                                                 if (!File.Exists (internalfullfilename)) {
877                                                         string message = "\"" + internalfullfilename + "\" doesn't exist. Please verify that you have entered the correct file name.";
878                                                         MessageBox.Show (message, openSaveButton.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
879                                                         
880                                                         return;
881                                                 }
882                                         }
883                                 } else {
884                                         if (overwritePrompt) {
885                                                 if (File.Exists (internalfullfilename)) {
886                                                         string message = "\"" + internalfullfilename + "\" exists. Overwrite ?";
887                                                         DialogResult dr = MessageBox.Show (message, openSaveButton.Text, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
888                                                         
889                                                         if (dr == DialogResult.Cancel)
890                                                                 return;
891                                                 }
892                                         }
893                                         
894                                         if (createPrompt) {
895                                                 if (!File.Exists (internalfullfilename)) {
896                                                         string message = "\"" + internalfullfilename + "\" doesn't exist. Create ?";
897                                                         DialogResult dr = MessageBox.Show (message, openSaveButton.Text, MessageBoxButtons.OKCancel, MessageBoxIcon.Warning);
898                                                         
899                                                         if (dr == DialogResult.Cancel)
900                                                                 return;
901                                                 }
902                                         }
903                                 }
904                                 
905                                 if (fileDialogType == FileDialogType.SaveFileDialog) {
906                                         if (addExtension) {
907                                                 string extension_to_use = String.Empty;
908                                                 string filter_exentsion = String.Empty;
909                                                 
910                                                 if (fileFilter != null) {
911                                                         FilterStruct filterstruct = (FilterStruct)fileFilter.FilterArrayList [filterIndex - 1];
912                                                         
913                                                         for (int i = 0; i < filterstruct.filters.Count; i++) {
914                                                                 string extension = filterstruct.filters [i];
915                                                                 
916                                                                 if (extension.StartsWith ("*"))
917                                                                         extension = extension.Remove (0, 1);
918                                                                 
919                                                                 if (extension.IndexOf ('*') != -1)
920                                                                         continue;
921                                                                 
922                                                                 filter_exentsion = extension;
923                                                                 break;
924                                                         }
925                                                 }
926                                                 
927                                                 if (filter_exentsion != String.Empty)
928                                                         extension_to_use = filter_exentsion;
929                                                 else
930                                                         if (DefaultExt.Length > 0)
931                                                                 extension_to_use = "." + DefaultExt;
932                                                 
933                                                 if (!internalfullfilename.EndsWith (extension_to_use))
934                                                         internalfullfilename += extension_to_use;
935                                         }
936                                 }
937
938                                 // do not use the FileName setter internally, as this will 
939                                 // cause the illegal character check to be skipped, and we
940                                 // do not want this for filename users have entered
941                                 fileNames = new string [1] { internalfullfilename };
942                                 
943                                 mwfFileView.WriteRecentlyUsed (internalfullfilename);
944                         } else // multiSelect = true
945                         if (fileDialogType != FileDialogType.SaveFileDialog) {
946                                 if (mwfFileView.SelectedItems.Count > 0) {
947                                         // first remove all selected directories
948                                         ArrayList al = new ArrayList ();
949                                         
950                                         foreach (FileViewListViewItem lvi in mwfFileView.SelectedItems) {
951                                                 FSEntry fsEntry = lvi.FSEntry;
952                                                 
953                                                 if (fsEntry.Attributes != FileAttributes.Directory) {
954                                                         al.Add (fsEntry);
955                                                 }
956                                         }
957                                         
958                                         fileNames = new string [al.Count];
959                                         
960                                         for (int i = 0; i < al.Count; i++) {
961                                                 fileNames [i] = ((FSEntry)al [i]).FullName;
962                                         }
963                                 }
964                         }
965                         
966                         if (checkPathExists && mwfFileView.CurrentRealFolder != null) {
967                                 if (!Directory.Exists (mwfFileView.CurrentRealFolder)) {
968                                         string message = "\"" + mwfFileView.CurrentRealFolder + "\" doesn't exist. Please verify that you have entered the correct directory name.";
969                                         MessageBox.Show (message, openSaveButton.Text, MessageBoxButtons.OK, MessageBoxIcon.Warning);
970
971                                         if (InitialDirectory.Length == 0 || !Directory.Exists (InitialDirectory))
972                                                 mwfFileView.ChangeDirectory (null, lastFolder);
973                                         else
974                                                 mwfFileView.ChangeDirectory (null, InitialDirectory);
975                                         return;
976                                 }
977                         }
978                         
979                         if (restoreDirectory) {
980                                 lastFolder  = restoreDirectoryString;
981                         } else {
982                                 lastFolder = mwfFileView.CurrentFolder;
983                         }
984
985                         foreach (string fileName in fileNames) {
986                                 if (!File.Exists (fileName))
987                                         // ignore files that do not exist
988                                         continue;
989
990                                 if (fileNameComboBox.Items.IndexOf (fileName) == -1)
991                                         fileNameComboBox.Items.Insert (0, fileName);
992                         }
993
994                         // remove items above the maximum items that we want to display
995                         while (fileNameComboBox.Items.Count > MaxFileNameItems)
996                                 fileNameComboBox.Items.RemoveAt (MaxFileNameItems);
997                         
998                         CancelEventArgs cancelEventArgs = new CancelEventArgs ();
999                         
1000                         cancelEventArgs.Cancel = false;
1001                         
1002                         OnFileOk (cancelEventArgs);
1003                         
1004                         form.DialogResult = DialogResult.OK;
1005                 }
1006                 
1007                 void OnClickCancelButton (object sender, EventArgs e)
1008                 {
1009                         if (restoreDirectory)
1010                                 mwfFileView.CurrentFolder = restoreDirectoryString;
1011                         
1012                         CancelEventArgs cancelEventArgs = new CancelEventArgs ();
1013                         
1014                         cancelEventArgs.Cancel = true;
1015                         
1016                         OnFileOk (cancelEventArgs);
1017                         
1018                         form.DialogResult = DialogResult.Cancel;
1019                 }
1020                 
1021                 void OnClickHelpButton (object sender, EventArgs e)
1022                 {
1023                         OnHelpRequest (e);
1024                 }
1025                 
1026                 void OnClickSmallButtonToolBar (object sender, ToolBarButtonClickEventArgs e)
1027                 {
1028                         if (e.Button == upToolBarButton) {
1029                                 mwfFileView.OneDirUp ();
1030                         } else
1031                         if (e.Button == backToolBarButton) {
1032                                 mwfFileView.PopDir ();
1033                         } else
1034                         if (e.Button == newdirToolBarButton) {
1035                                 mwfFileView.CreateNewFolder ();
1036                         }
1037                 }
1038                 
1039                 void OnSelectedIndexChangedFileTypeComboBox (object sender, EventArgs e)
1040                 {
1041                         if (do_not_call_OnSelectedIndexChangedFileTypeComboBox) {
1042                                 do_not_call_OnSelectedIndexChangedFileTypeComboBox = false;
1043                                 return;
1044                         }
1045                         
1046                         filterIndex = fileTypeComboBox.SelectedIndex + 1;
1047                         
1048                         mwfFileView.FilterIndex = filterIndex;
1049                 }
1050                 
1051                 void OnSelectedFileChangedFileView (object sender, EventArgs e)
1052                 {
1053                         fileNameComboBox.Text = mwfFileView.CurrentFSEntry.Name;
1054                 }
1055                 
1056                 void OnSelectedFilesChangedFileView (object sender, EventArgs e)
1057                 {
1058                         string selectedFiles = mwfFileView.SelectedFilesString;
1059                         if (selectedFiles != null && selectedFiles.Length != 0)
1060                                 fileNameComboBox.Text = selectedFiles;
1061                 }
1062                 
1063                 void OnForceDialogEndFileView (object sender, EventArgs e)
1064                 {
1065                         OnClickOpenSaveButton (this, EventArgs.Empty);
1066                 }
1067                 
1068                 void OnDirectoryChangedDirComboBox (object sender, EventArgs e)
1069                 {
1070                         mwfFileView.ChangeDirectory (sender, dirComboBox.CurrentFolder);
1071                 }
1072                 
1073                 void OnDirectoryChangedPopupButtonPanel (object sender, EventArgs e)
1074                 {
1075                         mwfFileView.ChangeDirectory (sender, popupButtonPanel.CurrentFolder);
1076                 }
1077                 
1078                 void OnCheckCheckChanged (object sender, EventArgs e)
1079                 {
1080                         ReadOnlyChecked = readonlyCheckBox.Checked;
1081                 }
1082
1083 #if NET_2_0             
1084                 void OnFileDialogFormClosed (object sender, FormClosedEventArgs e)
1085                 {
1086                         HandleFormClosedEvent (sender);
1087                 }
1088 #else
1089                 void OnFileDialogFormClosed (object sender, EventArgs e)
1090                 {
1091                         HandleFormClosedEvent (sender);
1092                 }
1093 #endif
1094                 
1095                 void HandleFormClosedEvent (object sender)
1096                 {
1097                         if (!disable_form_closed_event)
1098                                 OnClickCancelButton (sender, EventArgs.Empty);
1099                         
1100                         disable_form_closed_event = false;
1101                 }
1102                 
1103                 private void UpdateFilters ()
1104                 {
1105                         if (fileFilter == null)
1106                                 fileFilter = new FileFilter ();
1107                         
1108                         ArrayList filters = fileFilter.FilterArrayList;
1109                         
1110                         fileTypeComboBox.BeginUpdate ();
1111                         
1112                         fileTypeComboBox.Items.Clear ();
1113                         
1114                         foreach (FilterStruct fs in filters) {
1115                                 fileTypeComboBox.Items.Add (fs.filterName);
1116                         }
1117                         
1118                         if (filters.Count > 0 && FilterIndex <= filters.Count)
1119                                 fileTypeComboBox.SelectedIndex = filterIndex - 1;
1120                         
1121                         fileTypeComboBox.EndUpdate ();
1122                         
1123                         mwfFileView.FilterArrayList = filters;
1124                         
1125                         mwfFileView.FilterIndex = filterIndex;
1126                 }
1127                 
1128                 private void ResizeAndRelocateForHelpOrReadOnly ()
1129                 {
1130                         form.SuspendLayout ();
1131                         if (ShowHelp || ShowReadOnly) {
1132                                 mwfFileView.Size = new Size (449, 250); 
1133                                 fileNameLabel.Location = new Point (102, 298);
1134                                 fileNameComboBox.Location = new Point (195, 298);
1135                                 fileTypeLabel.Location = new Point (102, 324);
1136                                 fileTypeComboBox.Location = new Point (195, 324);
1137                                 openSaveButton.Location = new Point (475, 298);
1138                                 cancelButton.Location = new Point (475, 324);
1139                         } else {
1140                                 mwfFileView.Size = new Size (449, 282);
1141                                 fileNameLabel.Location = new Point (102, 330);
1142                                 fileNameComboBox.Location = new Point (195, 330);
1143                                 fileTypeLabel.Location = new Point (102, 356);
1144                                 fileTypeComboBox.Location = new Point (195, 356);
1145                                 openSaveButton.Location = new Point (475, 330);
1146                                 cancelButton.Location = new Point (475, 356);
1147                         }
1148                         
1149                         if (ShowHelp)
1150                                 form.Controls.Add (helpButton);
1151                         else
1152                                 form.Controls.Remove (helpButton);
1153                         
1154                         if (ShowReadOnly)
1155                                 form.Controls.Add (readonlyCheckBox);
1156                         else
1157                                 form.Controls.Remove (readonlyCheckBox);
1158                         form.ResumeLayout ();
1159                 }
1160                 
1161                 private void WriteConfigValues (CancelEventArgs ce)
1162                 {
1163                         MWFConfig.SetValue (filedialog_string, width_string, form.Width);
1164                         MWFConfig.SetValue (filedialog_string, height_string, form.Height);
1165                         MWFConfig.SetValue (filedialog_string, x_string, form.Location.X);
1166                         MWFConfig.SetValue (filedialog_string, y_string, form.Location.Y);
1167                         
1168                         if (!ce.Cancel) {
1169                                 MWFConfig.SetValue (filedialog_string, lastfolder_string, lastFolder);
1170                                 
1171                                 string[] fileNameCBItems = new string [fileNameComboBox.Items.Count];
1172                                 
1173                                 fileNameComboBox.Items.CopyTo (fileNameCBItems, 0);
1174                                 
1175                                 MWFConfig.SetValue (filedialog_string, filenames_string, fileNameCBItems);
1176                         }
1177                 }
1178                 
1179                 private void ReadConfigValues ()
1180                 {
1181                         lastFolder = (string)MWFConfig.GetValue (filedialog_string, lastfolder_string);
1182                         
1183                         if (lastFolder != null && lastFolder.IndexOf ("://") == -1) {
1184                                 if (!Directory.Exists (lastFolder)) {
1185                                         lastFolder = MWFVFS.DesktopPrefix;
1186                                 }
1187                         }
1188                         
1189                         if (InitialDirectory.Length > 0 && Directory.Exists (InitialDirectory))
1190                                 lastFolder = InitialDirectory;
1191                         else
1192                                 if (lastFolder == null || lastFolder.Length == 0)
1193                                         lastFolder = Environment.CurrentDirectory;
1194                         
1195                         if (RestoreDirectory)
1196                                 restoreDirectoryString = lastFolder;
1197                 }
1198         }
1199         #endregion
1200         
1201         #region PopupButtonPanel
1202         internal class PopupButtonPanel : Control, IUpdateFolder
1203         {
1204                 #region PopupButton
1205                 internal class PopupButton : Control
1206                 {
1207                         internal enum PopupButtonState
1208                         { Normal, Down, Up}
1209                         
1210                         private Image image = null;
1211                         private PopupButtonState popupButtonState = PopupButtonState.Normal;
1212                         private StringFormat text_format = new StringFormat();
1213                         private Rectangle text_rect = Rectangle.Empty;
1214                         
1215                         public PopupButton ()
1216                         {
1217                                 text_format.Alignment = StringAlignment.Center;
1218                                 text_format.LineAlignment = StringAlignment.Near;
1219                                 
1220                                 SetStyle (ControlStyles.DoubleBuffer, true);
1221                                 SetStyle (ControlStyles.AllPaintingInWmPaint, true);
1222                                 SetStyle (ControlStyles.UserPaint, true);
1223                                 SetStyle (ControlStyles.Selectable, false);
1224                         }
1225                         
1226                         public Image Image {
1227                                 set {
1228                                         image = value;
1229                                         Invalidate ();
1230                                 }
1231                                 
1232                                 get {
1233                                         return image;
1234                                 }
1235                         }
1236                         
1237                         public PopupButtonState ButtonState {
1238                                 set {
1239                                         popupButtonState = value;
1240                                         Invalidate ();
1241                                 }
1242                                 
1243                                 get {
1244                                         return popupButtonState;
1245                                 }
1246                         }
1247                         
1248                         protected override void OnPaint (PaintEventArgs pe)
1249                         {
1250                                 Draw (pe);
1251                                 
1252                                 base.OnPaint (pe);
1253                         }
1254                         
1255                         private void Draw (PaintEventArgs pe)
1256                         {
1257                                 Graphics gr = pe.Graphics;
1258                                 
1259                                 gr.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (BackColor), ClientRectangle);
1260                                 
1261                                 // draw image
1262                                 if (image != null) {
1263                                         int i_x = (ClientSize.Width - image.Width) / 2;
1264                                         int i_y = 4;
1265                                         gr.DrawImage (image, i_x, i_y);
1266                                 }
1267                                 
1268                                 if (Text != String.Empty) {
1269                                         if (text_rect == Rectangle.Empty)
1270                                                 text_rect = new Rectangle (0, Height - 30, Width, Height - 30); 
1271                                         
1272                                         gr.DrawString (Text, Font, Brushes.White, text_rect, text_format);
1273                                 }
1274                                 
1275                                 switch (popupButtonState) {
1276                                         case PopupButtonState.Up:
1277                                                 gr.DrawLine (ThemeEngine.Current.ResPool.GetPen (Color.White), 0, 0, ClientSize.Width - 1, 0);
1278                                                 gr.DrawLine (ThemeEngine.Current.ResPool.GetPen (Color.White), 0, 0, 0, ClientSize.Height - 1);
1279                                                 gr.DrawLine (ThemeEngine.Current.ResPool.GetPen (Color.Black), ClientSize.Width - 1, 0, ClientSize.Width - 1, ClientSize.Height - 1);
1280                                                 gr.DrawLine (ThemeEngine.Current.ResPool.GetPen (Color.Black), 0, ClientSize.Height - 1, ClientSize.Width - 1, ClientSize.Height - 1);
1281                                                 break;
1282                                                 
1283                                         case PopupButtonState.Down:
1284                                                 gr.DrawLine (ThemeEngine.Current.ResPool.GetPen (Color.Black), 0, 0, ClientSize.Width - 1, 0);
1285                                                 gr.DrawLine (ThemeEngine.Current.ResPool.GetPen (Color.Black), 0, 0, 0, ClientSize.Height - 1);
1286                                                 gr.DrawLine (ThemeEngine.Current.ResPool.GetPen (Color.White), ClientSize.Width - 1, 0, ClientSize.Width - 1, ClientSize.Height - 1);
1287                                                 gr.DrawLine (ThemeEngine.Current.ResPool.GetPen (Color.White), 0, ClientSize.Height - 1, ClientSize.Width - 1, ClientSize.Height - 1);
1288                                                 break;
1289                                 }
1290                         }
1291                         
1292                         protected override void OnMouseEnter (EventArgs e)
1293                         {
1294                                 if (popupButtonState != PopupButtonState.Down)
1295                                         popupButtonState = PopupButtonState.Up;
1296                                 
1297                                 PopupButtonPanel panel = Parent as PopupButtonPanel;
1298                                 
1299                                 if (panel.focusButton != null && panel.focusButton.ButtonState == PopupButtonState.Up) {
1300                                         panel.focusButton.ButtonState = PopupButtonState.Normal;
1301                                         panel.focusButton = null;
1302                                 }
1303                                 Invalidate ();
1304                                 base.OnMouseEnter (e);
1305                         }
1306                         
1307                         protected override void OnMouseLeave (EventArgs e)
1308                         {
1309                                 if (popupButtonState == PopupButtonState.Up)
1310                                         popupButtonState = PopupButtonState.Normal;
1311                                 Invalidate ();
1312                                 base.OnMouseLeave (e);
1313                         }
1314                         
1315                         protected override void OnClick (EventArgs e)
1316                         {
1317                                 popupButtonState = PopupButtonState.Down;
1318                                 Invalidate ();
1319                                 base.OnClick (e);
1320                         }
1321                 }
1322                 #endregion
1323                 
1324                 private PopupButton recentlyusedButton;
1325                 private PopupButton desktopButton;
1326                 private PopupButton personalButton;
1327                 private PopupButton mycomputerButton;
1328                 private PopupButton networkButton;
1329                 
1330                 private PopupButton lastPopupButton = null;
1331                 private PopupButton focusButton = null;
1332                 
1333                 private string currentPath;
1334                 
1335                 private int currentFocusIndex;
1336                 
1337                 public PopupButtonPanel ()
1338                 {
1339                         SuspendLayout ();
1340                         
1341                         BackColor = Color.FromArgb (128, 128, 128);
1342                         Size = new Size (85, 336);
1343                         
1344                         recentlyusedButton = new PopupButton ();
1345                         desktopButton = new PopupButton ();
1346                         personalButton = new PopupButton ();
1347                         mycomputerButton = new PopupButton ();
1348                         networkButton = new PopupButton ();
1349                         
1350                         recentlyusedButton.Size = new Size (81, 64);
1351                         recentlyusedButton.Image = ThemeEngine.Current.Images (UIIcon.PlacesRecentDocuments, 32);
1352                         recentlyusedButton.BackColor = BackColor;
1353                         recentlyusedButton.ForeColor = Color.Black;
1354                         recentlyusedButton.Location = new Point (2, 2);
1355                         recentlyusedButton.Text = "Recently\nused";
1356                         recentlyusedButton.Click += new EventHandler (OnClickButton);
1357                         
1358                         desktopButton.Image = ThemeEngine.Current.Images (UIIcon.PlacesDesktop, 32);
1359                         desktopButton.BackColor = BackColor;
1360                         desktopButton.ForeColor = Color.Black;
1361                         desktopButton.Size = new Size (81, 64);
1362                         desktopButton.Location = new Point (2, 66);
1363                         desktopButton.Text = "Desktop";
1364                         desktopButton.Click += new EventHandler (OnClickButton);
1365                         
1366                         personalButton.Image = ThemeEngine.Current.Images (UIIcon.PlacesPersonal, 32);
1367                         personalButton.BackColor = BackColor;
1368                         personalButton.ForeColor = Color.Black;
1369                         personalButton.Size = new Size (81, 64);
1370                         personalButton.Location = new Point (2, 130);
1371                         personalButton.Text = "Personal";
1372                         personalButton.Click += new EventHandler (OnClickButton);
1373                         
1374                         mycomputerButton.Image = ThemeEngine.Current.Images (UIIcon.PlacesMyComputer, 32);
1375                         mycomputerButton.BackColor = BackColor;
1376                         mycomputerButton.ForeColor = Color.Black;
1377                         mycomputerButton.Size = new Size (81, 64);
1378                         mycomputerButton.Location = new Point (2, 194);
1379                         mycomputerButton.Text = "My Computer";
1380                         mycomputerButton.Click += new EventHandler (OnClickButton);
1381                         
1382                         networkButton.Image = ThemeEngine.Current.Images (UIIcon.PlacesMyNetwork, 32);
1383                         networkButton.BackColor = BackColor;
1384                         networkButton.ForeColor = Color.Black;
1385                         networkButton.Size = new Size (81, 64);
1386                         networkButton.Location = new Point (2, 258);
1387                         networkButton.Text = "My Network";
1388                         networkButton.Click += new EventHandler (OnClickButton);
1389                         
1390                         Controls.Add (recentlyusedButton);
1391                         Controls.Add (desktopButton);
1392                         Controls.Add (personalButton);
1393                         Controls.Add (mycomputerButton);
1394                         Controls.Add (networkButton);
1395                         
1396                         ResumeLayout (false);
1397                         
1398                         KeyDown += new KeyEventHandler (Key_Down);
1399                         
1400                         SetStyle (ControlStyles.StandardClick, false);
1401                 }
1402                 
1403                 void OnClickButton (object sender, EventArgs e)
1404                 {
1405                         if (lastPopupButton != null && lastPopupButton != sender as PopupButton)
1406                                 lastPopupButton.ButtonState = PopupButton.PopupButtonState.Normal;
1407                         lastPopupButton = sender as PopupButton;
1408                         
1409                         if (sender == recentlyusedButton) {
1410                                 currentPath = MWFVFS.RecentlyUsedPrefix;
1411                         } else
1412                         if (sender == desktopButton) {
1413                                 currentPath = MWFVFS.DesktopPrefix;
1414                         } else
1415                         if (sender == personalButton) {
1416                                 currentPath = MWFVFS.PersonalPrefix;
1417                         } else
1418                         if (sender == mycomputerButton) {
1419                                 currentPath = MWFVFS.MyComputerPrefix;
1420                         } else
1421                         if (sender == networkButton) {
1422                                 currentPath = MWFVFS.MyNetworkPrefix;
1423                         }
1424                         
1425                         EventHandler eh = (EventHandler)(Events [PDirectoryChangedEvent]);
1426                         if (eh != null)
1427                                 eh (this, EventArgs.Empty);
1428                 }
1429                 
1430                 public string CurrentFolder {
1431                         set {
1432                                 string currentPath = value;
1433                                 if (currentPath == MWFVFS.RecentlyUsedPrefix) {
1434                                         if (lastPopupButton != recentlyusedButton) {
1435                                                 if (lastPopupButton != null)
1436                                                         lastPopupButton.ButtonState = PopupButton.PopupButtonState.Normal;
1437                                                 recentlyusedButton.ButtonState = PopupButton.PopupButtonState.Down;
1438                                                 lastPopupButton = recentlyusedButton;
1439                                         }
1440                                 } else
1441                                 if (currentPath == MWFVFS.DesktopPrefix) {
1442                                         if (lastPopupButton != desktopButton) {
1443                                                 if (lastPopupButton != null)
1444                                                         lastPopupButton.ButtonState = PopupButton.PopupButtonState.Normal;
1445                                                 desktopButton.ButtonState = PopupButton.PopupButtonState.Down;
1446                                                 lastPopupButton = desktopButton;
1447                                         }
1448                                 } else
1449                                 if (currentPath == MWFVFS.PersonalPrefix) {
1450                                         if (lastPopupButton != personalButton) {
1451                                                 if (lastPopupButton != null)
1452                                                         lastPopupButton.ButtonState = PopupButton.PopupButtonState.Normal;
1453                                                 personalButton.ButtonState = PopupButton.PopupButtonState.Down;
1454                                                 lastPopupButton = personalButton;
1455                                         }
1456                                 } else
1457                                 if (currentPath == MWFVFS.MyComputerPrefix) {
1458                                         if (lastPopupButton != mycomputerButton) {
1459                                                 if (lastPopupButton != null)
1460                                                         lastPopupButton.ButtonState = PopupButton.PopupButtonState.Normal;
1461                                                 mycomputerButton.ButtonState = PopupButton.PopupButtonState.Down;
1462                                                 lastPopupButton = mycomputerButton;
1463                                         }
1464                                 } else
1465                                 if (currentPath == MWFVFS.MyNetworkPrefix) {
1466                                         if (lastPopupButton != networkButton) {
1467                                                 if (lastPopupButton != null)
1468                                                         lastPopupButton.ButtonState = PopupButton.PopupButtonState.Normal;
1469                                                 networkButton.ButtonState = PopupButton.PopupButtonState.Down;
1470                                                 lastPopupButton = networkButton;
1471                                         }
1472                                 } else {
1473                                         if (lastPopupButton != null) {
1474                                                 lastPopupButton.ButtonState = PopupButton.PopupButtonState.Normal;
1475                                                 lastPopupButton = null;
1476                                         }
1477                                 }
1478                         }
1479                         get {
1480                                 return currentPath;
1481                         }
1482                 }
1483                 
1484                 protected override void OnPaint (PaintEventArgs e)
1485                 {
1486                         ControlPaint.DrawBorder3D (e.Graphics, ClientRectangle, Border3DStyle.Sunken);
1487                         base.OnPaint (e);
1488                 }
1489                 
1490                 protected override void OnGotFocus (EventArgs e)
1491                 {
1492                         if (lastPopupButton != recentlyusedButton) {
1493                                 recentlyusedButton.ButtonState = PopupButton.PopupButtonState.Up;
1494                                 focusButton = recentlyusedButton;
1495                         }
1496                         currentFocusIndex = 0;
1497                         
1498                         base.OnGotFocus (e);
1499                 }
1500                 
1501                 protected override void OnLostFocus (EventArgs e)
1502                 {
1503                         if (focusButton != null && focusButton.ButtonState != PopupButton.PopupButtonState.Down)
1504                                 focusButton.ButtonState = PopupButton.PopupButtonState.Normal;
1505                         base.OnLostFocus (e);
1506                 }
1507                 
1508                 protected override bool IsInputKey (Keys key)
1509                 {
1510                         switch (key) {
1511                                 case Keys.Up:
1512                                 case Keys.Down:
1513                                 case Keys.Right:
1514                                 case Keys.Left:
1515                                 case Keys.Enter:
1516                                         return true;
1517                         }
1518                         return base.IsInputKey (key);
1519                 }
1520                 
1521                 private void Key_Down (object sender, KeyEventArgs e)
1522                 {
1523                         bool update_focus = false;
1524                         
1525                         if (e.KeyCode == Keys.Left || e.KeyCode == Keys.Up) {
1526                                 currentFocusIndex --;
1527                                 
1528                                 if (currentFocusIndex < 0)
1529                                         currentFocusIndex = Controls.Count - 1;
1530                                 
1531                                 update_focus = true;
1532                         } else
1533                         if (e.KeyCode == Keys.Down || e.KeyCode == Keys.Right) {
1534                                 currentFocusIndex++;
1535                                 
1536                                 if (currentFocusIndex == Controls.Count)
1537                                         currentFocusIndex = 0;
1538                                 
1539                                 update_focus = true;
1540                         } else
1541                         if (e.KeyCode == Keys.Enter) {
1542                                 focusButton.ButtonState = PopupButton.PopupButtonState.Down;
1543                                 OnClickButton (focusButton, EventArgs.Empty);
1544                         }
1545                         
1546                         if (update_focus) {
1547                                 PopupButton newfocusButton = Controls [currentFocusIndex] as PopupButton;
1548                                 if (focusButton != null && focusButton.ButtonState != PopupButton.PopupButtonState.Down)
1549                                         focusButton.ButtonState = PopupButton.PopupButtonState.Normal;
1550                                 if (newfocusButton.ButtonState != PopupButton.PopupButtonState.Down)
1551                                         newfocusButton.ButtonState = PopupButton.PopupButtonState.Up;
1552                                 focusButton = newfocusButton;
1553                         }
1554                         
1555                         e.Handled = true;
1556                 }
1557                 
1558                 static object PDirectoryChangedEvent = new object ();
1559                 
1560                 public event EventHandler DirectoryChanged {
1561                         add { Events.AddHandler (PDirectoryChangedEvent, value); }
1562                         remove { Events.RemoveHandler (PDirectoryChangedEvent, value); }
1563                 }
1564         }
1565         #endregion
1566         
1567         #region DirComboBox
1568         internal class DirComboBox : ComboBox, IUpdateFolder
1569         {
1570                 #region DirComboBoxItem
1571                 internal class DirComboBoxItem
1572                 {
1573                         private int imageIndex;
1574                         private string name;
1575                         private string path;
1576                         private int xPos;
1577                         private ImageList imageList;
1578                         
1579                         public DirComboBoxItem (ImageList imageList, int imageIndex, string name, string path, int xPos)
1580                         {
1581                                 this.imageList = imageList;
1582                                 this.imageIndex = imageIndex;
1583                                 this.name = name;
1584                                 this.path = path;
1585                                 this.xPos = xPos;
1586                         }
1587                         
1588                         public int ImageIndex {
1589                                 get {
1590                                         return imageIndex;
1591                                 }
1592                         }
1593                         
1594                         public string Name {
1595                                 get {
1596                                         return name;
1597                                 }
1598                         }
1599                         
1600                         public string Path {
1601                                 get {
1602                                         return path;
1603                                 }
1604                         }
1605                         
1606                         public int XPos {
1607                                 get {
1608                                         return xPos;
1609                                 }
1610                         }
1611                         
1612                         public ImageList ImageList {
1613                                 set {
1614                                         imageList = value;
1615                                 }
1616                                 
1617                                 get {
1618                                         return imageList;
1619                                 }
1620                         }
1621                 }
1622                 #endregion
1623                 
1624                 private ImageList imageList = new ImageList();
1625                 
1626                 private string currentPath;
1627                 
1628                 private Stack folderStack = new Stack();
1629                 
1630                 private static readonly int indent = 6;
1631                 
1632                 private DirComboBoxItem recentlyUsedDirComboboxItem;
1633                 private DirComboBoxItem desktopDirComboboxItem;
1634                 private DirComboBoxItem personalDirComboboxItem;
1635                 private DirComboBoxItem myComputerDirComboboxItem;
1636                 private DirComboBoxItem networkDirComboboxItem;
1637                 
1638                 private ArrayList myComputerItems = new ArrayList ();
1639                 
1640                 private DirComboBoxItem mainParentDirComboBoxItem = null;
1641                 private DirComboBoxItem real_parent = null;
1642                 
1643                 private MWFVFS vfs;
1644                 
1645                 public DirComboBox (MWFVFS vfs)
1646                 {
1647                         this.vfs = vfs;
1648
1649                         SuspendLayout ();
1650                         
1651                         DrawMode = DrawMode.OwnerDrawFixed;
1652                         
1653                         imageList.ColorDepth = ColorDepth.Depth32Bit;
1654                         imageList.ImageSize = new Size (16, 16);
1655                         imageList.Images.Add (ThemeEngine.Current.Images (UIIcon.PlacesRecentDocuments, 16));
1656                         imageList.Images.Add (ThemeEngine.Current.Images (UIIcon.PlacesDesktop, 16));
1657                         imageList.Images.Add (ThemeEngine.Current.Images (UIIcon.PlacesPersonal, 16));
1658                         imageList.Images.Add (ThemeEngine.Current.Images (UIIcon.PlacesMyComputer, 16));
1659                         imageList.Images.Add (ThemeEngine.Current.Images (UIIcon.PlacesMyNetwork, 16));
1660                         imageList.Images.Add (ThemeEngine.Current.Images (UIIcon.NormalFolder, 16));
1661                         imageList.TransparentColor = Color.Transparent;
1662                         
1663                         recentlyUsedDirComboboxItem = new DirComboBoxItem (imageList, 0, "Recently used", MWFVFS.RecentlyUsedPrefix, 0);
1664                         desktopDirComboboxItem = new DirComboBoxItem (imageList, 1, "Desktop", MWFVFS.DesktopPrefix, 0);
1665                         personalDirComboboxItem = new DirComboBoxItem (imageList, 2, "Personal folder", MWFVFS.PersonalPrefix, indent);
1666                         myComputerDirComboboxItem = new DirComboBoxItem (imageList, 3, "My Computer", MWFVFS.MyComputerPrefix, indent);
1667                         networkDirComboboxItem = new DirComboBoxItem (imageList, 4, "My Network", MWFVFS.MyNetworkPrefix, indent);
1668                         
1669                         ArrayList al = this.vfs.GetMyComputerContent ();
1670                         
1671                         foreach (FSEntry fsEntry in al) {
1672                                 myComputerItems.Add (new DirComboBoxItem (MimeIconEngine.LargeIcons, fsEntry.IconIndex, fsEntry.Name, fsEntry.FullName, indent * 2));
1673                         }
1674                         
1675                         al.Clear ();
1676                         al = null;
1677                         
1678                         mainParentDirComboBoxItem = myComputerDirComboboxItem;
1679                         
1680                         ResumeLayout (false);
1681                 }
1682                 
1683                 public string CurrentFolder {
1684                         set {
1685                                 currentPath = value;
1686                                 
1687                                 CreateComboList ();
1688                         }
1689                         get {
1690                                 return currentPath;
1691                         }
1692                 }
1693                 
1694                 private void CreateComboList ()
1695                 {
1696                         real_parent = null;
1697                         DirComboBoxItem selection = null;
1698                         
1699                         if (currentPath == MWFVFS.RecentlyUsedPrefix) {
1700                                 mainParentDirComboBoxItem = recentlyUsedDirComboboxItem;
1701                                 selection = recentlyUsedDirComboboxItem;
1702                         } else
1703                         if (currentPath == MWFVFS.DesktopPrefix) {
1704                                 selection = desktopDirComboboxItem;
1705                                 mainParentDirComboBoxItem = desktopDirComboboxItem;
1706                         } else
1707                         if (currentPath == MWFVFS.PersonalPrefix) {
1708                                 selection = personalDirComboboxItem;
1709                                 mainParentDirComboBoxItem = personalDirComboboxItem;
1710                         } else
1711                         if (currentPath == MWFVFS.MyComputerPrefix) {
1712                                 selection = myComputerDirComboboxItem;
1713                                 mainParentDirComboBoxItem = myComputerDirComboboxItem;
1714                         } else
1715                         if (currentPath == MWFVFS.MyNetworkPrefix) {
1716                                 selection = networkDirComboboxItem;
1717                                 mainParentDirComboBoxItem = networkDirComboboxItem;
1718                         } else {
1719                                 foreach (DirComboBoxItem dci in myComputerItems) {
1720                                         if (dci.Path == currentPath) {
1721                                                 mainParentDirComboBoxItem = selection = dci;
1722                                                 break;
1723                                         }
1724                                 }
1725                         }
1726                         
1727                         BeginUpdate ();
1728                         
1729                         Items.Clear ();
1730                         
1731                         Items.Add (recentlyUsedDirComboboxItem);
1732                         Items.Add (desktopDirComboboxItem);
1733                         Items.Add (personalDirComboboxItem);
1734                         Items.Add (myComputerDirComboboxItem);
1735                         Items.AddRange (myComputerItems);
1736                         Items.Add (networkDirComboboxItem);
1737                         
1738                         if (selection == null) {
1739                                 real_parent = CreateFolderStack ();
1740                         }
1741                         
1742                         if (real_parent != null) {
1743                                 int local_indent = 0;
1744                                 
1745                                 if (real_parent == desktopDirComboboxItem)
1746                                         local_indent = 1;
1747                                 else
1748                                 if (real_parent == personalDirComboboxItem || real_parent == networkDirComboboxItem)
1749                                         local_indent = 2;
1750                                 else
1751                                         local_indent = 3;
1752                                 
1753                                 selection = AppendToParent (local_indent, real_parent);
1754                         }
1755                         
1756                         EndUpdate ();
1757                         
1758                         if (selection != null)
1759                                 SelectedItem = selection;
1760                 }
1761                 
1762                 private DirComboBoxItem CreateFolderStack ()
1763                 {
1764                         folderStack.Clear ();
1765                         
1766                         DirectoryInfo di = new DirectoryInfo (currentPath);
1767                         
1768                         folderStack.Push (di);
1769                         
1770                         while (di.Parent != null) {
1771                                 di = di.Parent;
1772                                 
1773                                 if (mainParentDirComboBoxItem != personalDirComboboxItem && di.FullName == ThemeEngine.Current.Places (UIIcon.PlacesDesktop))
1774                                         return desktopDirComboboxItem;
1775                                 else
1776                                 if (mainParentDirComboBoxItem == personalDirComboboxItem) {
1777                                         if (di.FullName == ThemeEngine.Current.Places (UIIcon.PlacesPersonal))
1778                                                 return personalDirComboboxItem;
1779                                 } else
1780                                         foreach (DirComboBoxItem dci in myComputerItems) {
1781                                                 if (dci.Path == di.FullName) {
1782                                                         return dci;
1783                                                 }
1784                                         }
1785                                 
1786                                 
1787                                 folderStack.Push (di);
1788                         }
1789                         
1790                         return null;
1791                 }
1792                 
1793                 private DirComboBoxItem AppendToParent (int nr_indents, DirComboBoxItem parentDirComboBoxItem)
1794                 {
1795                         DirComboBoxItem selection = null;
1796                         
1797                         int index = Items.IndexOf (parentDirComboBoxItem) + 1;
1798                         
1799                         int xPos = indent * nr_indents;
1800                         
1801                         while (folderStack.Count != 0) {
1802                                 DirectoryInfo dii = folderStack.Pop () as DirectoryInfo;
1803                                 
1804                                 DirComboBoxItem dci = new DirComboBoxItem (imageList, 5, dii.Name, dii.FullName, xPos);
1805                                 
1806                                 Items.Insert (index, dci);
1807                                 index++;
1808                                 selection = dci;
1809                                 xPos += indent;
1810                         }
1811                         
1812                         return selection;
1813                 }
1814                 
1815                 protected override void OnDrawItem (DrawItemEventArgs e)
1816                 {
1817                         if (e.Index == -1)
1818                                 return;
1819                         
1820                         DirComboBoxItem dcbi = Items [e.Index] as DirComboBoxItem;
1821                         
1822                         Bitmap bmp = new Bitmap (e.Bounds.Width, e.Bounds.Height, e.Graphics);
1823                         Graphics gr = Graphics.FromImage (bmp);
1824                         
1825                         Color backColor = e.BackColor;
1826                         Color foreColor = e.ForeColor;
1827                         
1828                         int xPos = dcbi.XPos;
1829
1830                         if ((e.State & DrawItemState.ComboBoxEdit) != 0)
1831                                 xPos = 0;
1832
1833                         gr.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (backColor),
1834                                         new Rectangle (0, 0, bmp.Width, bmp.Height));
1835                         
1836                         if ((e.State & DrawItemState.Selected) == DrawItemState.Selected &&
1837                                         (!DroppedDown || (e.State & DrawItemState.ComboBoxEdit) != DrawItemState.ComboBoxEdit)) {
1838                                 foreColor = ThemeEngine.Current.ColorHighlightText;
1839
1840                                 int w = (int) gr.MeasureString (dcbi.Name, e.Font).Width;
1841
1842                                 gr.FillRectangle (ThemeEngine.Current.ResPool.GetSolidBrush (ThemeEngine.Current.ColorHighlight),
1843                                                 new Rectangle (xPos + 23, 1, w + 3, e.Bounds.Height - 2));
1844                                 if ((e.State & DrawItemState.Focus) == DrawItemState.Focus) {
1845                                         ControlPaint.DrawFocusRectangle (gr, new Rectangle (xPos + 22, 0, w + 5,
1846                                                         e.Bounds.Height), foreColor, ThemeEngine.Current.ColorHighlight);
1847                                 }
1848                         }
1849
1850                         gr.DrawString (dcbi.Name, e.Font , ThemeEngine.Current.ResPool.GetSolidBrush (foreColor), new Point (24 + xPos, (bmp.Height - e.Font.Height) / 2));
1851                         gr.DrawImage (dcbi.ImageList.Images [dcbi.ImageIndex], new Rectangle (new Point (xPos + 2, 0), new Size (16, 16)));
1852                         
1853                         e.Graphics.DrawImage (bmp, e.Bounds.X, e.Bounds.Y);
1854                         gr.Dispose ();
1855                         bmp.Dispose ();
1856                 }
1857                 
1858                 protected override void OnSelectedIndexChanged (EventArgs e)
1859                 {
1860                         if (Items.Count > 0) {
1861                                 DirComboBoxItem dcbi = Items [SelectedIndex] as DirComboBoxItem;
1862                                 
1863                                 currentPath = dcbi.Path;
1864                         }
1865                 }
1866                 
1867                 protected override void OnSelectionChangeCommitted (EventArgs e)
1868                 {
1869                         EventHandler eh = (EventHandler)(Events [CDirectoryChangedEvent]);
1870                         if (eh != null)
1871                                 eh (this, EventArgs.Empty);
1872                 }
1873                 
1874                 static object CDirectoryChangedEvent = new object ();
1875                 
1876                 public event EventHandler DirectoryChanged {
1877                         add { Events.AddHandler (CDirectoryChangedEvent, value); }
1878                         remove { Events.RemoveHandler (CDirectoryChangedEvent, value); }
1879                 }
1880         }
1881         #endregion
1882         
1883         #region FilterStruct
1884         internal struct FilterStruct
1885         {
1886                 public string filterName;
1887                 public StringCollection filters;
1888                 
1889                 public FilterStruct (string filterName, string filter)
1890                 {
1891                         this.filterName = filterName;
1892                         
1893                         filters =  new StringCollection ();
1894                         
1895                         SplitFilters (filter);
1896                 }
1897                 
1898                 private void SplitFilters (string filter)
1899                 {
1900                         string[] split = filter.Split (new char [] {';'});
1901                         foreach (string s in split) {
1902                                 filters.Add (s.Trim ());
1903                         }
1904                 }
1905         }
1906         #endregion
1907         
1908         #region FileFilter
1909         internal class FileFilter
1910         {
1911                 private ArrayList filterArrayList = new ArrayList();
1912                 
1913                 private string filter;
1914                 
1915                 public FileFilter ()
1916                 {}
1917                 
1918                 public FileFilter (string filter) : base ()
1919                 {
1920                         this.filter = filter;
1921                         
1922                         SplitFilter ();
1923                 }
1924                 
1925                 public static bool CheckFilter (string val)
1926                 {
1927                         if (val.Length == 0)
1928                                 return true;
1929                         
1930                         string[] filters = val.Split (new char [] {'|'});
1931                         
1932                         if ((filters.Length % 2) != 0)
1933                                 return false;
1934                         
1935                         return true;
1936                 }
1937                 
1938                 public ArrayList FilterArrayList {
1939                         set {
1940                                 filterArrayList = value;
1941                         }
1942                         
1943                         get {
1944                                 return filterArrayList;
1945                         }
1946                 }
1947                 
1948                 public string Filter {
1949                         set {
1950                                 filter = value;
1951                                 
1952                                 SplitFilter ();
1953                         }
1954                         
1955                         get {
1956                                 return filter;
1957                         }
1958                 }
1959                 
1960                 private void SplitFilter ()
1961                 {
1962                         filterArrayList.Clear ();
1963                         
1964                         if (filter.Length == 0)
1965                                 return;
1966                         
1967                         string[] filters = filter.Split (new char [] {'|'});
1968                         
1969                         for (int i = 0; i < filters.Length; i += 2) {
1970                                 FilterStruct filterStruct = new FilterStruct (filters [i], filters [i + 1]);
1971                                 
1972                                 filterArrayList.Add (filterStruct);
1973                         }
1974                 }
1975         }
1976         #endregion
1977         
1978         #region MWFFileView             
1979         // MWFFileView
1980         internal class MWFFileView : ListView
1981         {
1982                 private ArrayList filterArrayList;
1983                 
1984                 private bool showHiddenFiles = false;
1985                 
1986                 private string selectedFilesString;
1987                 
1988                 private int filterIndex = 1;
1989                 
1990                 private ToolTip toolTip;
1991                 private int oldItemIndexForToolTip = -1;
1992                 
1993                 private ContextMenu contextMenu;
1994                 
1995                 private MenuItem menuItemView;
1996                 private MenuItem menuItemNew;
1997                 
1998                 private MenuItem smallIconMenutItem;
1999                 private MenuItem tilesMenutItem;
2000                 private MenuItem largeIconMenutItem;
2001                 private MenuItem listMenutItem;
2002                 private MenuItem detailsMenutItem;
2003                 
2004                 private MenuItem newFolderMenuItem; 
2005                 private MenuItem showHiddenFilesMenuItem;
2006                 
2007                 private int previousCheckedMenuItemIndex;
2008                 
2009                 private ArrayList viewMenuItemClones = new ArrayList ();
2010                 
2011                 private FSEntry currentFSEntry = null;
2012                 
2013                 private string currentFolder;
2014                 private string currentRealFolder;
2015                 private FSEntry currentFolderFSEntry;
2016                 
2017                 // store DirectoryInfo for a back button for example
2018                 private Stack directoryStack = new Stack();
2019                 
2020                 // list of controls(components to enable or disable depending on current directoryStack.Count
2021                 private ArrayList dirStackControlsOrComponents = new ArrayList ();
2022                 
2023                 private ToolBarButton folderUpToolBarButton;
2024                 
2025                 private ArrayList registered_senders = new ArrayList ();
2026                 
2027                 private bool should_push = true;
2028                 
2029                 private MWFVFS vfs;
2030                 
2031                 private View old_view;
2032                 
2033                 private int old_menuitem_index;
2034                 private bool do_update_view = false;
2035                 
2036                 private int platform = (int) Environment.OSVersion.Platform;
2037                 
2038                 public MWFFileView (MWFVFS vfs)
2039                 {
2040                         this.vfs = vfs;
2041                         this.vfs.RegisterUpdateDelegate (new MWFVFS.UpdateDelegate (RealFileViewUpdate), this);
2042                         
2043                         SuspendLayout ();
2044                         
2045                         contextMenu = new ContextMenu ();
2046                         
2047                         toolTip = new ToolTip ();
2048                         toolTip.InitialDelay = 300;
2049                         toolTip.ReshowDelay = 0; 
2050                         
2051                         // contextMenu
2052                         
2053                         // View menu item
2054                         menuItemView = new MenuItem ("View");
2055                         
2056                         smallIconMenutItem = new MenuItem ("Small Icon", new EventHandler (OnClickViewMenuSubItem));
2057                         smallIconMenutItem.RadioCheck = true;
2058                         menuItemView.MenuItems.Add (smallIconMenutItem);
2059                         
2060                         tilesMenutItem = new MenuItem ("Tiles", new EventHandler (OnClickViewMenuSubItem));
2061                         tilesMenutItem.RadioCheck = true;
2062                         menuItemView.MenuItems.Add (tilesMenutItem);
2063                         
2064                         largeIconMenutItem = new MenuItem ("Large Icon", new EventHandler (OnClickViewMenuSubItem));
2065                         largeIconMenutItem.RadioCheck = true;
2066                         menuItemView.MenuItems.Add (largeIconMenutItem);
2067                         
2068                         listMenutItem = new MenuItem ("List", new EventHandler (OnClickViewMenuSubItem));
2069                         listMenutItem.RadioCheck = true;
2070                         listMenutItem.Checked = true;
2071                         menuItemView.MenuItems.Add (listMenutItem);
2072                         previousCheckedMenuItemIndex = listMenutItem.Index;
2073                         
2074                         detailsMenutItem = new MenuItem ("Details", new EventHandler (OnClickViewMenuSubItem));
2075                         detailsMenutItem.RadioCheck = true;
2076                         menuItemView.MenuItems.Add (detailsMenutItem);
2077                         
2078                         contextMenu.MenuItems.Add (menuItemView);
2079                         
2080                         contextMenu.MenuItems.Add (new MenuItem ("-"));
2081                         
2082                         // New menu item
2083                         menuItemNew = new MenuItem ("New");
2084                         
2085                         newFolderMenuItem = new MenuItem ("New Folder", new EventHandler (OnClickNewFolderMenuItem));
2086                         menuItemNew.MenuItems.Add (newFolderMenuItem);
2087                         
2088                         contextMenu.MenuItems.Add (menuItemNew);
2089                         
2090                         contextMenu.MenuItems.Add (new MenuItem ("-"));
2091                         
2092                         // Show hidden files menu item
2093                         showHiddenFilesMenuItem = new MenuItem ("Show hidden files", new EventHandler (OnClickContextMenu));
2094                         showHiddenFilesMenuItem.Checked = showHiddenFiles;
2095                         contextMenu.MenuItems.Add (showHiddenFilesMenuItem);
2096                         
2097                         LabelWrap = true;
2098                         
2099                         SmallImageList = MimeIconEngine.SmallIcons;
2100                         LargeImageList = MimeIconEngine.LargeIcons;
2101                         
2102                         View = old_view = View.List;
2103                         LabelEdit = true;
2104                         
2105                         ContextMenu = contextMenu;
2106                         
2107                         ResumeLayout (false);
2108                         
2109                         KeyDown += new KeyEventHandler (MWF_KeyDown);
2110                 }
2111                 
2112                 public string CurrentFolder {
2113                         get {
2114                                 return currentFolder;
2115                         }
2116                         set {
2117                                 currentFolder = value;
2118                         }
2119                 }
2120                 
2121                 public string CurrentRealFolder {
2122                         get {
2123                                 return currentRealFolder;
2124                         }
2125                 }
2126                 
2127                 public FSEntry CurrentFSEntry {
2128                         get {
2129                                 return currentFSEntry;
2130                         }
2131                 }
2132                 
2133                 public MenuItem[] ViewMenuItems {
2134                         get {
2135                                 MenuItem[] menuItemClones = new MenuItem [] {
2136                                         smallIconMenutItem.CloneMenu (),
2137                                         tilesMenutItem.CloneMenu (),
2138                                         largeIconMenutItem.CloneMenu (),
2139                                         listMenutItem.CloneMenu (),
2140                                         detailsMenutItem.CloneMenu ()
2141                                 };
2142                                 
2143                                 viewMenuItemClones.Add (menuItemClones);
2144                                 
2145                                 return menuItemClones;
2146                         }
2147                 }
2148                 
2149                 public ArrayList FilterArrayList {
2150                         set {
2151                                 filterArrayList = value;
2152                         }
2153                         
2154                         get {
2155                                 return filterArrayList;
2156                         }
2157                 }
2158                 
2159                 public bool ShowHiddenFiles {
2160                         set {
2161                                 showHiddenFiles = value;
2162                         }
2163                         
2164                         get {
2165                                 return showHiddenFiles;
2166                         }
2167                 }
2168                 
2169                 public int FilterIndex {
2170                         set {
2171                                 filterIndex = value;
2172                                 if (Visible)
2173                                         UpdateFileView ();
2174                         }
2175                         
2176                         get {
2177                                 return filterIndex;
2178                         }
2179                 }
2180                 
2181                 public string SelectedFilesString {
2182                         set {
2183                                 selectedFilesString = value;
2184                         }
2185                         
2186                         get {
2187                                 return selectedFilesString;
2188                         }
2189                 }
2190                 
2191                 public void PushDir ()
2192                 {
2193                         if (currentFolder != null)
2194                                 directoryStack.Push (currentFolder);
2195                         
2196                         EnableOrDisableDirstackObjects ();
2197                 }
2198                 
2199                 public void PopDir ()
2200                 {
2201                         if (directoryStack.Count == 0)
2202                                 return;
2203                         
2204                         string new_folder = directoryStack.Pop () as string;
2205                         
2206                         EnableOrDisableDirstackObjects ();
2207                         
2208                         should_push = false;
2209                         
2210                         ChangeDirectory (null, new_folder);
2211                 }
2212                 
2213                 public void RegisterSender (IUpdateFolder iud)
2214                 {
2215                         registered_senders.Add (iud);
2216                 }
2217                 
2218                 public void CreateNewFolder ()
2219                 {
2220                         if (currentFolder == MWFVFS.MyComputerPrefix ||
2221                             currentFolder == MWFVFS.RecentlyUsedPrefix)
2222                                 return;
2223                         
2224                         FSEntry fsEntry = new FSEntry ();
2225                         fsEntry.Attributes = FileAttributes.Directory;
2226                         fsEntry.FileType = FSEntry.FSEntryType.Directory;
2227                         fsEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("inode/directory");
2228                         fsEntry.LastAccessTime = DateTime.Now;
2229                         
2230                         // FIXME: when ListView.LabelEdit is available use it
2231 //                      listViewItem.BeginEdit();
2232                         
2233                         TextEntryDialog ted = new TextEntryDialog ();
2234                         ted.IconPictureBoxImage = MimeIconEngine.LargeIcons.Images.GetImage (fsEntry.IconIndex);
2235                         
2236                         string folder = String.Empty;
2237                         
2238                         if (currentFolderFSEntry.RealName != null)
2239                                 folder = currentFolderFSEntry.RealName;
2240                         else
2241                                 folder = currentFolder;
2242                         
2243                         string tmp_filename = "New Folder";
2244                         
2245                         if (Directory.Exists (Path.Combine (folder, tmp_filename))) {
2246                                 int i = 1;
2247                                 
2248                                 if ((platform == 4) || (platform == 128)) {
2249                                         tmp_filename = tmp_filename + "-" + i;
2250                                 } else {
2251                                         tmp_filename = tmp_filename + " (" + i + ")";
2252                                 }
2253                                 
2254                                 while (Directory.Exists (Path.Combine (folder, tmp_filename))) {
2255                                         i++;
2256                                         if ((platform == 4) || (platform == 128)) {
2257                                                 tmp_filename = "New Folder" + "-" + i;
2258                                         } else {
2259                                                 tmp_filename = "New Folder" + " (" + i + ")";
2260                                         }
2261                                 }
2262                         }
2263                         
2264                         ted.FileName = tmp_filename;
2265                         
2266                         if (ted.ShowDialog () == DialogResult.OK) {
2267                                 string new_folder = Path.Combine (folder, ted.FileName);
2268                                 
2269                                 if (vfs.CreateFolder (new_folder)) {
2270                                         fsEntry.FullName = new_folder;
2271                                         fsEntry.Name = ted.FileName;
2272                                         
2273                                         FileViewListViewItem listViewItem = new FileViewListViewItem (fsEntry);
2274                                         
2275                                         BeginUpdate ();
2276                                         Items.Add (listViewItem);
2277                                         EndUpdate ();
2278                                         
2279                                         listViewItem.EnsureVisible ();
2280                                 }
2281                         }
2282                 }
2283                 
2284                 public void SetSelectedIndexTo (string fname)
2285                 {
2286                         foreach (FileViewListViewItem item in Items) {
2287                                 if (item.Text == fname) {
2288                                         BeginUpdate ();
2289                                         SelectedItems.Clear ();
2290                                         item.Selected = true;
2291                                         EndUpdate ();
2292                                         break;
2293                                 }
2294                         }
2295                 }
2296                 
2297                 public void OneDirUp ()
2298                 {
2299                         string parent_folder = vfs.GetParent ();
2300                         if (parent_folder != null)
2301                                 ChangeDirectory (null, parent_folder);
2302                 }
2303                 
2304                 public void ChangeDirectory (object sender, string folder)
2305                 {
2306                         if (folder == MWFVFS.DesktopPrefix || folder == MWFVFS.RecentlyUsedPrefix)
2307                                 folderUpToolBarButton.Enabled = false;
2308                         else
2309                                 folderUpToolBarButton.Enabled = true;
2310                         
2311                         foreach (IUpdateFolder iuf in registered_senders) {
2312                                 iuf.CurrentFolder = folder;
2313                         }
2314                         
2315                         if (should_push)
2316                                 PushDir ();
2317                         else
2318                                 should_push = true;
2319                         
2320                         currentFolderFSEntry = vfs.ChangeDirectory (folder);
2321                         
2322                         currentFolder = folder;
2323                         
2324                         if (currentFolder.IndexOf ("://") != -1)
2325                                 currentRealFolder = currentFolderFSEntry.RealName;
2326                         else
2327                                 currentRealFolder = currentFolder;
2328                         
2329                         BeginUpdate ();
2330                         
2331                         Items.Clear ();
2332                         SelectedItems.Clear ();
2333                         
2334                         if (folder == MWFVFS.RecentlyUsedPrefix) {
2335                                 old_view = View;
2336                                 View = View.Details;
2337                                 old_menuitem_index = previousCheckedMenuItemIndex;
2338                                 UpdateMenuItems (detailsMenutItem);
2339                                 do_update_view = true;
2340                         } else
2341                         if (View != old_view && do_update_view) {
2342                                 UpdateMenuItems (menuItemView.MenuItems [old_menuitem_index]);
2343                                 View = old_view;
2344                                 do_update_view = false;
2345                         }
2346                         EndUpdate ();
2347
2348                         try {
2349                                 UpdateFileView ();
2350                         } catch (Exception e) {
2351                                 if (should_push)
2352                                         PopDir ();
2353                                 MessageBox.Show (e.Message, "Error", MessageBoxButtons.OK, MessageBoxIcon.Error);
2354                         }
2355                 }
2356                 
2357                 public void UpdateFileView ()
2358                 {
2359                         if (filterArrayList != null && filterArrayList.Count != 0) {
2360                                 FilterStruct fs = (FilterStruct)filterArrayList [filterIndex - 1];
2361                                 
2362                                 vfs.GetFolderContent (fs.filters);
2363                         } else
2364                                 vfs.GetFolderContent ();
2365                 }
2366                 
2367                 public void RealFileViewUpdate (ArrayList directoriesArrayList, ArrayList fileArrayList)
2368                 {
2369                         BeginUpdate ();
2370                         
2371                         Items.Clear ();
2372                         SelectedItems.Clear ();
2373                         
2374                         foreach (FSEntry directoryFSEntry in directoriesArrayList) {
2375                                 if (!ShowHiddenFiles)
2376                                         if (directoryFSEntry.Name.StartsWith (".") || directoryFSEntry.Attributes == FileAttributes.Hidden)
2377                                                 continue;
2378                                 
2379                                 FileViewListViewItem listViewItem = new FileViewListViewItem (directoryFSEntry);
2380                                 
2381                                 Items.Add (listViewItem);
2382                         }
2383                         
2384                         StringCollection collection = new StringCollection ();
2385                         
2386                         foreach (FSEntry fsEntry in fileArrayList) {
2387                                 
2388                                 // remove duplicates. that can happen when you read recently used files for example
2389                                 if (collection.Contains (fsEntry.Name)) {
2390                                         
2391                                         string fileName = fsEntry.Name;
2392                                         
2393                                         if (collection.Contains (fileName)) {
2394                                                 int i = 1;
2395                                                 
2396                                                 while (collection.Contains (fileName + "(" + i + ")")) {
2397                                                         i++;
2398                                                 }
2399                                                 
2400                                                 fileName = fileName + "(" + i + ")";
2401                                         }
2402                                         
2403                                         fsEntry.Name = fileName;
2404                                 }
2405                                 
2406                                 collection.Add (fsEntry.Name);
2407                                 
2408                                 DoOneFSEntry (fsEntry);
2409                         }
2410                         
2411                         EndUpdate ();
2412                         
2413                         collection.Clear ();
2414                         collection = null;
2415                         
2416                         directoriesArrayList.Clear ();
2417                         fileArrayList.Clear ();
2418                 }
2419                 
2420                 public void AddControlToEnableDisableByDirStack (object control)
2421                 {
2422                         dirStackControlsOrComponents.Add (control);
2423                 }
2424                 
2425                 public void SetFolderUpToolBarButton (ToolBarButton tb)
2426                 {
2427                         folderUpToolBarButton = tb;
2428                 }
2429                 
2430                 public void WriteRecentlyUsed (string fullfilename)
2431                 {
2432                         vfs.WriteRecentlyUsedFiles (fullfilename);
2433                 }
2434                 
2435                 private void EnableOrDisableDirstackObjects ()
2436                 {
2437                         foreach (object o in dirStackControlsOrComponents) {
2438                                 if (o is Control) {
2439                                         Control c = o as Control;
2440                                         c.Enabled = (directoryStack.Count > 1);
2441                                 } else
2442                                 if (o is ToolBarButton) {
2443                                         ToolBarButton t = o as ToolBarButton;
2444                                         t.Enabled = (directoryStack.Count > 0);
2445                                 }
2446                         }
2447                 }
2448                 
2449                 private void DoOneFSEntry (FSEntry fsEntry) 
2450                 {
2451                         if (!ShowHiddenFiles)
2452                                 if (fsEntry.Name.StartsWith (".")  || fsEntry.Attributes == FileAttributes.Hidden)
2453                                         return;
2454                         
2455                         FileViewListViewItem listViewItem = new FileViewListViewItem (fsEntry);
2456                         
2457                         Items.Add (listViewItem);
2458                 }
2459                 
2460                 private void MWF_KeyDown (object sender, KeyEventArgs e)
2461                 {
2462                         if (e.KeyCode == Keys.Back) {
2463                                 OneDirUp ();
2464                         }
2465                 }
2466                 
2467                 protected override void OnClick (EventArgs e)
2468                 {
2469                         if (!MultiSelect) {
2470                                 if (SelectedItems.Count > 0) {
2471                                         FileViewListViewItem listViewItem = SelectedItems [0] as FileViewListViewItem;
2472                                         
2473                                         FSEntry fsEntry = listViewItem.FSEntry;
2474                                         
2475                                         if (fsEntry.FileType == FSEntry.FSEntryType.File) {
2476                                                 currentFSEntry = fsEntry;
2477                                                 
2478                                                 EventHandler eh = (EventHandler)(Events [MSelectedFileChangedEvent]);
2479                                                 if (eh != null)
2480                                                         eh (this, EventArgs.Empty);
2481                                         }
2482                                 }
2483                         }
2484                         
2485                         base.OnClick (e);
2486                 }
2487                 
2488                 protected override void OnDoubleClick (EventArgs e)
2489                 {
2490                         if (SelectedItems.Count > 0) {
2491                                 FileViewListViewItem listViewItem = SelectedItems [0] as FileViewListViewItem;
2492                                 
2493                                 FSEntry fsEntry = listViewItem.FSEntry;
2494                                 
2495                                 if (fsEntry.Attributes == FileAttributes.Directory) {
2496                                         
2497                                         ChangeDirectory (null, fsEntry.FullName);
2498                                         
2499                                         EventHandler eh = (EventHandler)(Events [MDirectoryChangedEvent]);
2500                                         if (eh != null)
2501                                                 eh (this, EventArgs.Empty);
2502                                 } else {
2503                                         currentFSEntry = fsEntry;
2504                                         
2505                                         EventHandler eh = (EventHandler)(Events [MSelectedFileChangedEvent]);
2506                                         if (eh != null)
2507                                                 eh (this, EventArgs.Empty);
2508                                         
2509                                         eh = (EventHandler)(Events [MForceDialogEndEvent]);
2510                                         if (eh != null)
2511                                                 eh (this, EventArgs.Empty);
2512                                         
2513                                         return;
2514                                 }
2515                         }
2516                         
2517                         base.OnDoubleClick (e);
2518                 }
2519                 
2520                 protected override void OnSelectedIndexChanged (EventArgs e)
2521                 {
2522                         if (SelectedItems.Count > 0) {
2523                                 selectedFilesString = String.Empty;
2524                                 
2525                                 if (SelectedItems.Count == 1) {
2526                                         FileViewListViewItem listViewItem = SelectedItems [0] as FileViewListViewItem;
2527                                         
2528                                         FSEntry fsEntry = listViewItem.FSEntry;
2529
2530                                         if (fsEntry.Attributes != FileAttributes.Directory)
2531                                                 selectedFilesString = SelectedItems [0].Text;
2532                                 } else {
2533                                         foreach (FileViewListViewItem lvi in SelectedItems) {
2534                                                 FSEntry fsEntry = lvi.FSEntry;
2535
2536                                                 if (fsEntry.Attributes != FileAttributes.Directory)
2537                                                         selectedFilesString = selectedFilesString + "\"" + lvi.Text + "\" ";
2538                                         }
2539                                 }
2540
2541                                 EventHandler eh = (EventHandler)(Events [MSelectedFilesChangedEvent]);
2542                                 if (eh != null)
2543                                         eh (this, EventArgs.Empty);
2544                         }
2545
2546                         base.OnSelectedIndexChanged (e);
2547                 }
2548                 
2549                 protected override void OnMouseMove (MouseEventArgs e)
2550                 {
2551                         FileViewListViewItem item = GetItemAt (e.X, e.Y) as FileViewListViewItem;
2552                         
2553                         if (item != null) {
2554                                 int currentItemIndex = item.Index;
2555                                 
2556                                 if (currentItemIndex != oldItemIndexForToolTip) {
2557                                         oldItemIndexForToolTip = currentItemIndex;
2558                                         
2559                                         if (toolTip != null && toolTip.Active)
2560                                                 toolTip.Active = false;
2561                                         
2562                                         FSEntry fsEntry = item.FSEntry;
2563                                         
2564                                         string output = String.Empty;
2565                                         
2566                                         if (fsEntry.FileType == FSEntry.FSEntryType.Directory)
2567                                                 output = "Directory: " + fsEntry.FullName;
2568                                         else if (fsEntry.FileType == FSEntry.FSEntryType.Device)
2569                                                 output = "Device: "+ fsEntry.FullName;
2570                                         else if (fsEntry.FileType == FSEntry.FSEntryType.Network)
2571                                                 output = "Network: " + fsEntry.FullName;
2572                                         else
2573                                                 output = "File: " + fsEntry.FullName;
2574                                         
2575                                         toolTip.SetToolTip (this, output);      
2576                                         
2577                                         toolTip.Active = true;
2578                                 }
2579                         } else
2580                                 toolTip.Active = false;
2581                         
2582                         base.OnMouseMove (e);
2583                 }
2584                 
2585                 void OnClickContextMenu (object sender, EventArgs e)
2586                 {
2587                         MenuItem senderMenuItem = sender as MenuItem;
2588                         
2589                         if (senderMenuItem == showHiddenFilesMenuItem) {
2590                                 senderMenuItem.Checked = !senderMenuItem.Checked;
2591                                 showHiddenFiles = senderMenuItem.Checked;
2592                                 UpdateFileView ();
2593                         }
2594                 }
2595                 
2596                 void OnClickViewMenuSubItem (object sender, EventArgs e)
2597                 {
2598                         MenuItem senderMenuItem = (MenuItem)sender;
2599                         
2600                         UpdateMenuItems (senderMenuItem);
2601                         
2602                         // update me
2603                         
2604                         switch (senderMenuItem.Index) {
2605                                 case 0:
2606                                         View = View.SmallIcon;
2607                                         break;
2608                                 case 1:
2609                                         View = View.LargeIcon;
2610                                         break;
2611                                 case 2:
2612                                         View = View.LargeIcon;
2613                                         break;
2614                                 case 3:
2615                                         View = View.List;
2616                                         break;
2617                                 case 4:
2618                                         View = View.Details;
2619                                         break;
2620                                 default:
2621                                         break;
2622                         }
2623                 }
2624
2625                 protected override void OnBeforeLabelEdit (LabelEditEventArgs e)
2626                 {
2627                         FileViewListViewItem listViewItem = SelectedItems [0] as FileViewListViewItem;
2628                         FSEntry fsEntry = listViewItem.FSEntry;
2629
2630                         // only allow editing of files or directories
2631                         if (fsEntry.FileType != FSEntry.FSEntryType.Directory &&
2632                                 fsEntry.FileType != FSEntry.FSEntryType.File)
2633                                 e.CancelEdit = true;
2634
2635                         base.OnBeforeLabelEdit (e);
2636                 }
2637
2638                 protected override void OnAfterLabelEdit (LabelEditEventArgs e)
2639                 {
2640                         base.OnAfterLabelEdit (e);
2641
2642                         // no changes were made
2643                         if (e.Label == null || Items [e.Item].Text == e.Label)
2644                                 return;
2645
2646                         FileViewListViewItem listViewItem = SelectedItems [0] as FileViewListViewItem;
2647                         FSEntry fsEntry = listViewItem.FSEntry;
2648
2649                         string folder = (currentFolderFSEntry.RealName != null) ?
2650                                 currentFolderFSEntry.RealName : currentFolder;
2651
2652                         switch (fsEntry.FileType) {
2653                         case FSEntry.FSEntryType.Directory:
2654                                 string sourceDir = (fsEntry.RealName != null) ? fsEntry.RealName : fsEntry.FullName;
2655                                 string destDir = Path.Combine (folder, e.Label);
2656                                 if (!vfs.MoveFolder (sourceDir, destDir)) {
2657                                         e.CancelEdit = true;
2658                                 } else {
2659                                         if (fsEntry.RealName != null)
2660                                                 fsEntry.RealName = destDir;
2661                                         else
2662                                                 fsEntry.FullName = destDir;
2663                                 }
2664                                 break;
2665                         case FSEntry.FSEntryType.File:
2666                                 string sourceFile = (fsEntry.RealName != null) ? fsEntry.RealName : fsEntry.FullName;
2667                                 string destFile = Path.Combine (folder, e.Label);
2668                                 if (!vfs.MoveFile (sourceFile, destFile)) {
2669                                         e.CancelEdit = true;
2670                                 } else {
2671                                         if (fsEntry.RealName != null)
2672                                                 fsEntry.RealName = destFile;
2673                                         else
2674                                                 fsEntry.FullName = destFile;
2675                                 }
2676                                 break;
2677                         }
2678                 }
2679
2680                 private void UpdateMenuItems (MenuItem senderMenuItem)
2681                 {
2682                         menuItemView.MenuItems [previousCheckedMenuItemIndex].Checked = false;
2683                         menuItemView.MenuItems [senderMenuItem.Index].Checked = true;
2684                         
2685                         foreach (MenuItem[] items in viewMenuItemClones) {
2686                                 items [previousCheckedMenuItemIndex].Checked = false;
2687                                 items [senderMenuItem.Index].Checked = true;
2688                         }
2689                         
2690                         previousCheckedMenuItemIndex = senderMenuItem.Index;
2691                 }
2692                 
2693                 void OnClickNewFolderMenuItem (object sender, EventArgs e)
2694                 {
2695                         CreateNewFolder ();
2696                 }
2697                 
2698                 static object MSelectedFileChangedEvent = new object ();
2699                 static object MSelectedFilesChangedEvent = new object ();
2700                 static object MDirectoryChangedEvent = new object ();
2701                 static object MForceDialogEndEvent = new object ();
2702                 
2703                 public event EventHandler SelectedFileChanged {
2704                         add { Events.AddHandler (MSelectedFileChangedEvent, value); }
2705                         remove { Events.RemoveHandler (MSelectedFileChangedEvent, value); }
2706                 }
2707                 
2708                 public event EventHandler SelectedFilesChanged {
2709                         add { Events.AddHandler (MSelectedFilesChangedEvent, value); }
2710                         remove { Events.RemoveHandler (MSelectedFilesChangedEvent, value); }
2711                 }
2712                 
2713                 public event EventHandler DirectoryChanged {
2714                         add { Events.AddHandler (MDirectoryChangedEvent, value); }
2715                         remove { Events.RemoveHandler (MDirectoryChangedEvent, value); }
2716                 }
2717                 
2718                 public event EventHandler ForceDialogEnd {
2719                         add { Events.AddHandler (MForceDialogEndEvent, value); }
2720                         remove { Events.RemoveHandler (MForceDialogEndEvent, value); }
2721                 }
2722         }
2723         #endregion
2724         
2725         #region FileListViewItem
2726         internal class FileViewListViewItem : ListViewItem
2727         {
2728                 private FSEntry fsEntry;
2729                 
2730                 public FileViewListViewItem (FSEntry fsEntry)
2731                 {
2732                         this.fsEntry = fsEntry;
2733                         
2734                         ImageIndex = fsEntry.IconIndex;
2735                         
2736                         Text = fsEntry.Name;
2737                         
2738                         switch (fsEntry.FileType) {
2739                                 case FSEntry.FSEntryType.Directory:
2740                                         SubItems.Add (String.Empty);
2741                                         SubItems.Add ("Directory");
2742                                         SubItems.Add (fsEntry.LastAccessTime.ToShortDateString () + " " + fsEntry.LastAccessTime.ToShortTimeString ()); 
2743                                         break;
2744                                 case FSEntry.FSEntryType.File:
2745                                         long fileLen = 1;
2746                                         try {
2747                                                 if (fsEntry.FileSize > 1024)
2748                                                         fileLen = fsEntry.FileSize / 1024;
2749                                         } catch (Exception) {
2750                                                 fileLen = 1;
2751                                         }
2752                                         
2753                                         SubItems.Add (fileLen.ToString () + " KB");
2754                                         SubItems.Add ("File");
2755                                         SubItems.Add (fsEntry.LastAccessTime.ToShortDateString () + " " + fsEntry.LastAccessTime.ToShortTimeString ()); 
2756                                         break;
2757                                 case FSEntry.FSEntryType.Device:
2758                                         SubItems.Add (String.Empty);
2759                                         SubItems.Add ("Device");
2760                                         SubItems.Add (fsEntry.LastAccessTime.ToShortDateString () + " " + fsEntry.LastAccessTime.ToShortTimeString ()); 
2761                                         break;
2762                                 case FSEntry.FSEntryType.RemovableDevice:
2763                                         SubItems.Add (String.Empty);
2764                                         SubItems.Add ("RemovableDevice");
2765                                         SubItems.Add (fsEntry.LastAccessTime.ToShortDateString () + " " + fsEntry.LastAccessTime.ToShortTimeString ()); 
2766                                         break;
2767                                 default:
2768                                         break;
2769                         }
2770                 }
2771                 
2772                 public FSEntry FSEntry {
2773                         set {
2774                                 fsEntry = value;
2775                         }
2776                         
2777                         get {
2778                                 return fsEntry;
2779                         }
2780                 }
2781         }
2782         #endregion
2783         
2784         #region IUpdateFolder
2785         internal interface IUpdateFolder
2786         {
2787                 string CurrentFolder {get; set;}
2788         }
2789         #endregion
2790         
2791         #region TextEntryDialog
2792         // FIXME: When ListView.LabelEdit is implemented remove me
2793         internal class TextEntryDialog : Form
2794         {
2795                 private Label label1;
2796                 private Button okButton;
2797                 private TextBox newNameTextBox;
2798                 private PictureBox iconPictureBox;
2799                 private Button cancelButton;
2800                 private GroupBox groupBox1;
2801                 
2802                 public TextEntryDialog ()
2803                 {
2804                         groupBox1 = new GroupBox ();
2805                         cancelButton = new Button ();
2806                         iconPictureBox = new PictureBox ();
2807                         newNameTextBox = new TextBox ();
2808                         okButton = new Button ();
2809                         label1 = new Label ();
2810                         groupBox1.SuspendLayout ();
2811                         SuspendLayout ();
2812                         
2813                         // groupBox1
2814                         groupBox1.Controls.Add (newNameTextBox);
2815                         groupBox1.Controls.Add (label1);
2816                         groupBox1.Controls.Add (iconPictureBox);
2817                         groupBox1.Location = new Point (8, 8);
2818                         groupBox1.Size = new Size (232, 160);
2819                         groupBox1.TabIndex = 5;
2820                         groupBox1.TabStop = false;
2821                         groupBox1.Text = "New Name";
2822                         
2823                         // cancelButton
2824                         cancelButton.DialogResult = DialogResult.Cancel;
2825                         cancelButton.Location = new Point (168, 176);
2826                         cancelButton.TabIndex = 4;
2827                         cancelButton.Text = "Cancel";
2828                         
2829                         // iconPictureBox
2830                         iconPictureBox.BorderStyle = BorderStyle.Fixed3D;
2831                         iconPictureBox.Location = new Point (86, 24);
2832                         iconPictureBox.Size = new Size (60, 60);
2833                         iconPictureBox.TabIndex = 3;
2834                         iconPictureBox.TabStop = false;
2835                         iconPictureBox.SizeMode = PictureBoxSizeMode.CenterImage;
2836                         
2837                         // newNameTextBox
2838                         newNameTextBox.Location = new Point (16, 128);
2839                         newNameTextBox.Size = new Size (200, 20);
2840                         newNameTextBox.TabIndex = 5;
2841                         newNameTextBox.Text = String.Empty;
2842                         
2843                         // okButton
2844                         okButton.DialogResult = DialogResult.OK;
2845                         okButton.Location = new Point (80, 176);
2846                         okButton.TabIndex = 3;
2847                         okButton.Text = "OK";
2848                         
2849                         // label1
2850                         label1.Location = new Point (16, 96);
2851                         label1.Size = new Size (200, 23);
2852                         label1.TabIndex = 4;
2853                         label1.Text = "Enter Name:";
2854                         label1.TextAlign = ContentAlignment.MiddleCenter;
2855                         
2856                         // MainForm
2857                         AcceptButton = okButton;
2858                         AutoScaleBaseSize = new Size (5, 13);
2859                         CancelButton = cancelButton;
2860                         ClientSize = new Size (248, 205);
2861                         Controls.Add (groupBox1);
2862                         Controls.Add (cancelButton);
2863                         Controls.Add (okButton);
2864                         FormBorderStyle = FormBorderStyle.FixedDialog;
2865                         Text = "New Folder or File";
2866                         groupBox1.ResumeLayout (false);
2867                         ResumeLayout (false);
2868                         
2869                         newNameTextBox.Select ();
2870                 }
2871                 
2872                 public Image IconPictureBoxImage {
2873                         set {
2874                                 iconPictureBox.Image = value;
2875                         }
2876                 }
2877                 
2878                 public string FileName {
2879                         get {
2880                                 return newNameTextBox.Text;
2881                         }
2882                         set {
2883                                 newNameTextBox.Text = value;
2884                         }
2885                 }
2886         }
2887         #endregion
2888         
2889         #region MWFVFS  
2890         internal class MWFVFS
2891         {
2892                 private FileSystem fileSystem;
2893                 
2894                 private int platform = (int) Environment.OSVersion.Platform;
2895                 
2896                 public static readonly string DesktopPrefix = "Desktop://";
2897                 public static readonly string PersonalPrefix = "Personal://";
2898                 public static readonly string MyComputerPrefix = "MyComputer://";
2899                 public static readonly string RecentlyUsedPrefix = "RecentlyUsed://";
2900                 public static readonly string MyNetworkPrefix = "MyNetwork://";
2901                 public static readonly string MyComputerPersonalPrefix = "MyComputerPersonal://";
2902                 
2903                 public static Hashtable MyComputerDevicesPrefix = new Hashtable ();
2904                 
2905                 public delegate void UpdateDelegate (ArrayList folders, ArrayList files);
2906                 private UpdateDelegate updateDelegate;
2907                 private Control calling_control;
2908                 
2909                 private ThreadStart get_folder_content_thread_start;
2910                 private Thread worker;
2911                 private WorkerThread workerThread = null;
2912                 private StringCollection the_filters;
2913                 
2914                 public MWFVFS ()
2915                 {
2916                         if ((platform == 4) || (platform == 128)) {
2917                                 fileSystem = new UnixFileSystem ();
2918                         } else {
2919                                 fileSystem = new WinFileSystem ();
2920                         }
2921                 }
2922                 
2923                 public FSEntry ChangeDirectory (string folder)
2924                 {
2925                         return fileSystem.ChangeDirectory (folder);
2926                 }
2927                 
2928                 public void GetFolderContent ()
2929                 {
2930                         GetFolderContent (null);
2931                 }
2932                 
2933                 public void GetFolderContent (StringCollection filters)
2934                 {
2935                         the_filters = filters;
2936
2937                         if (workerThread != null) {
2938                                 workerThread.Stop ();
2939                                 workerThread = null;
2940                         }
2941
2942                         // Added next line to ensure the control is created before BeginInvoke is called on it
2943                         calling_control.CreateControl();
2944                         workerThread = new WorkerThread (fileSystem, the_filters, updateDelegate, calling_control);
2945                         
2946                         get_folder_content_thread_start = new ThreadStart (workerThread.GetFolderContentThread);
2947                         worker = new Thread (get_folder_content_thread_start);
2948                         worker.IsBackground = true;
2949                         worker.Start();
2950                 }
2951                 
2952                 internal class WorkerThread
2953                 {
2954                         private FileSystem fileSystem;
2955                         private StringCollection the_filters;
2956                         private UpdateDelegate updateDelegate;
2957                         private Control calling_control;
2958                         private readonly object lockobject = new object ();
2959                         private bool stopped = false;
2960                         
2961                         public WorkerThread (FileSystem fileSystem, StringCollection the_filters, UpdateDelegate updateDelegate, Control calling_control)
2962                         {
2963                                 this.fileSystem = fileSystem;
2964                                 this.the_filters = the_filters;
2965                                 this.updateDelegate = updateDelegate;
2966                                 this.calling_control = calling_control;
2967                         }
2968                         
2969                         public void GetFolderContentThread()
2970                         {
2971                                 ArrayList folders;
2972                                 ArrayList files;
2973                                 
2974                                 fileSystem.GetFolderContent (the_filters, out folders, out files);
2975                                 
2976                                 if (stopped)
2977                                         return;
2978                                 
2979                                 if (updateDelegate != null) {
2980                                         lock (this) {
2981                                                 object[] objectArray = new object[2];
2982                                                 
2983                                                 objectArray[0] = folders;
2984                                                 objectArray[1] = files;
2985                                                 
2986                                                 calling_control.BeginInvoke (updateDelegate, objectArray);
2987                                         }
2988                                 }
2989                         }
2990                         
2991                         public void Stop ()
2992                         {
2993                                 lock (lockobject) {
2994                                         stopped = true;
2995                                 }
2996                         }
2997                 }
2998                 
2999                 public ArrayList GetFoldersOnly ()
3000                 {
3001                         return fileSystem.GetFoldersOnly ();
3002                 }
3003                 
3004                 public void WriteRecentlyUsedFiles (string filename)
3005                 {
3006                         fileSystem.WriteRecentlyUsedFiles (filename);
3007                 }
3008                 
3009                 public ArrayList GetRecentlyUsedFiles ()
3010                 {
3011                         return fileSystem.GetRecentlyUsedFiles ();
3012                 }
3013                 
3014                 public ArrayList GetMyComputerContent ()
3015                 {
3016                         return fileSystem.GetMyComputerContent ();
3017                 }
3018                 
3019                 public ArrayList GetMyNetworkContent ()
3020                 {
3021                         return fileSystem.GetMyNetworkContent ();
3022                 }
3023                 
3024                 public bool CreateFolder (string new_folder)
3025                 {
3026                         try {
3027                                 if (Directory.Exists (new_folder)) {
3028                                         string message = "Folder \"" + new_folder + "\" already exists.";
3029                                         MessageBox.Show (message, new_folder, MessageBoxButtons.OK,
3030                                                 MessageBoxIcon.Error);
3031                                         return false;
3032                                 } else
3033                                         Directory.CreateDirectory (new_folder);
3034                         } catch (Exception e) {
3035                                 MessageBox.Show (e.Message, new_folder, MessageBoxButtons.OK, MessageBoxIcon.Error);
3036                                 return false;
3037                         }
3038                         
3039                         return true;
3040                 }
3041
3042                 public bool MoveFolder (string sourceDirName, string destDirName)
3043                 {
3044                         try {
3045                                 if (Directory.Exists (destDirName)) {
3046                                         string message = "Cannot rename " + Path.GetFileName (sourceDirName)
3047                                                 + ": A folder with the name you specified already exists."
3048                                                 + " Specify a different folder name.";
3049                                         MessageBox.Show (message, "Error Renaming Folder", MessageBoxButtons.OK,
3050                                                 MessageBoxIcon.Error);
3051                                         return false;
3052                                 } else
3053                                         Directory.Move (sourceDirName, destDirName);
3054                         } catch (Exception e) {
3055                                 MessageBox.Show (e.Message, "Error Renaming Folder", 
3056                                         MessageBoxButtons.OK, MessageBoxIcon.Error);
3057                                 return false;
3058                         }
3059
3060                         return true;
3061                 }
3062
3063                 public bool MoveFile (string sourceFileName, string destFileName)
3064                 {
3065                         try {
3066                                 if (File.Exists (destFileName)) {
3067                                         string message = "Cannot rename " + Path.GetFileName (sourceFileName)
3068                                                 + ": A file with the name you specified already exists."
3069                                                 + " Specify a different file name.";
3070                                         MessageBox.Show (message, "Error Renaming File",
3071                                                 MessageBoxButtons.OK, MessageBoxIcon.Error);
3072                                         return false;
3073                                 } else
3074                                         File.Move (sourceFileName, destFileName);
3075                         } catch (Exception e) {
3076                                 MessageBox.Show (e.Message, "Error Renaming Folder",
3077                                         MessageBoxButtons.OK, MessageBoxIcon.Error);
3078                                 return false;
3079                         }
3080
3081                         return true;
3082                 }
3083
3084                 public string GetParent ()
3085                 {
3086                         return fileSystem.GetParent ();
3087                 }
3088                 
3089                 public void RegisterUpdateDelegate(UpdateDelegate updateDelegate, Control control)
3090                 {
3091                         this.updateDelegate = updateDelegate;
3092                         calling_control = control;
3093                 }
3094         }
3095         #endregion
3096         
3097         #region FileSystem
3098         internal abstract class FileSystem
3099         {
3100                 protected string currentTopFolder = String.Empty;
3101                 protected FSEntry currentFolderFSEntry = null;
3102                 protected FSEntry currentTopFolderFSEntry = null;
3103                 private FileInfoComparer fileInfoComparer = new FileInfoComparer ();
3104                 
3105                 public FSEntry ChangeDirectory (string folder)
3106                 {
3107                         if (folder == MWFVFS.DesktopPrefix) {
3108                                 currentTopFolder = MWFVFS.DesktopPrefix;
3109                                 currentTopFolderFSEntry = currentFolderFSEntry = GetDesktopFSEntry ();
3110                         } else
3111                         if (folder == MWFVFS.PersonalPrefix) {
3112                                 currentTopFolder = MWFVFS.PersonalPrefix;
3113                                 currentTopFolderFSEntry = currentFolderFSEntry = GetPersonalFSEntry ();
3114                         } else
3115                         if (folder == MWFVFS.MyComputerPersonalPrefix) {
3116                                 currentTopFolder = MWFVFS.MyComputerPersonalPrefix;
3117                                 currentTopFolderFSEntry = currentFolderFSEntry = GetMyComputerPersonalFSEntry ();
3118                         } else
3119                         if (folder == MWFVFS.RecentlyUsedPrefix) {
3120                                 currentTopFolder = MWFVFS.RecentlyUsedPrefix;
3121                                 currentTopFolderFSEntry = currentFolderFSEntry = GetRecentlyUsedFSEntry ();
3122                         } else
3123                         if (folder == MWFVFS.MyComputerPrefix) {
3124                                 currentTopFolder = MWFVFS.MyComputerPrefix;
3125                                 currentTopFolderFSEntry = currentFolderFSEntry = GetMyComputerFSEntry ();
3126                         } else
3127                         if (folder == MWFVFS.MyNetworkPrefix) {
3128                                 currentTopFolder = MWFVFS.MyNetworkPrefix;
3129                                 currentTopFolderFSEntry = currentFolderFSEntry = GetMyNetworkFSEntry ();
3130                         } else {
3131                                 bool found = false;
3132                                 
3133                                 foreach (DictionaryEntry entry in MWFVFS.MyComputerDevicesPrefix) {
3134                                         FSEntry fsEntry = entry.Value as FSEntry;
3135                                         if (folder == fsEntry.FullName) {
3136                                                 currentTopFolder = entry.Key as string;
3137                                                 currentTopFolderFSEntry = currentFolderFSEntry = fsEntry;
3138                                                 found = true;
3139                                                 break;
3140                                         }
3141                                 }
3142                                 
3143                                 if (!found) {
3144                                         currentFolderFSEntry = GetDirectoryFSEntry (new DirectoryInfo (folder), currentTopFolderFSEntry);
3145                                 }
3146                         }
3147                         
3148                         return currentFolderFSEntry;
3149                 }
3150                 
3151                 public string GetParent ()
3152                 {
3153                         return currentFolderFSEntry.Parent;
3154                 }
3155                 
3156                 // directories_out and files_out contain FSEntry objects
3157                 public void GetFolderContent (StringCollection filters, out ArrayList directories_out, out ArrayList files_out)
3158                 {
3159                         directories_out = new ArrayList ();
3160                         files_out = new ArrayList ();
3161                         
3162                         if (currentFolderFSEntry.FullName == MWFVFS.DesktopPrefix) {
3163                                 FSEntry personalFSEntry = GetPersonalFSEntry ();
3164                                 
3165                                 directories_out.Add (personalFSEntry);
3166                                 
3167                                 FSEntry myComputerFSEntry = GetMyComputerFSEntry ();
3168                                 
3169                                 directories_out.Add (myComputerFSEntry);
3170                                 
3171                                 FSEntry myNetworkFSEntry = GetMyNetworkFSEntry ();
3172                                 
3173                                 directories_out.Add (myNetworkFSEntry);
3174                                 
3175                                 ArrayList d_out = null;
3176                                 ArrayList f_out = null;
3177                                 GetNormalFolderContent (ThemeEngine.Current.Places (UIIcon.PlacesDesktop), filters, out d_out, out f_out);
3178                                 directories_out.AddRange (d_out);
3179                                 files_out.AddRange (f_out);
3180                                 
3181                         } else
3182                         if (currentFolderFSEntry.FullName == MWFVFS.RecentlyUsedPrefix) {
3183                                 files_out = GetRecentlyUsedFiles ();
3184                         } else
3185                         if (currentFolderFSEntry.FullName == MWFVFS.MyComputerPrefix) {
3186                                 directories_out.AddRange (GetMyComputerContent ());
3187                         } else
3188                         if (currentFolderFSEntry.FullName == MWFVFS.PersonalPrefix || currentFolderFSEntry.FullName == MWFVFS.MyComputerPersonalPrefix) {
3189                                 ArrayList d_out = null;
3190                                 ArrayList f_out = null;
3191                                 GetNormalFolderContent (ThemeEngine.Current.Places (UIIcon.PlacesPersonal), filters, out d_out, out f_out);
3192                                 directories_out.AddRange (d_out);
3193                                 files_out.AddRange (f_out);
3194                         } else
3195                         if (currentFolderFSEntry.FullName == MWFVFS.MyNetworkPrefix) {
3196                                 directories_out.AddRange (GetMyNetworkContent ());
3197                         } else {
3198                                 GetNormalFolderContent (currentFolderFSEntry.FullName, filters, out directories_out, out files_out);
3199                         }
3200                 }
3201                 
3202                 public ArrayList GetFoldersOnly ()
3203                 {
3204                         ArrayList directories_out = new ArrayList ();
3205                         
3206                         if (currentFolderFSEntry.FullName == MWFVFS.DesktopPrefix) {
3207                                 FSEntry personalFSEntry = GetPersonalFSEntry ();
3208                                 
3209                                 directories_out.Add (personalFSEntry);
3210                                 
3211                                 FSEntry myComputerFSEntry = GetMyComputerFSEntry ();
3212                                 
3213                                 directories_out.Add (myComputerFSEntry);
3214                                 
3215                                 FSEntry myNetworkFSEntry = GetMyNetworkFSEntry ();
3216                                 
3217                                 directories_out.Add (myNetworkFSEntry);
3218                                 
3219                                 ArrayList d_out = GetNormalFolders (ThemeEngine.Current.Places (UIIcon.PlacesDesktop));
3220                                 directories_out.AddRange (d_out);
3221                                 
3222                         } else
3223                         if (currentFolderFSEntry.FullName == MWFVFS.RecentlyUsedPrefix) {
3224                                 //files_out = GetRecentlyUsedFiles ();
3225                         } else
3226                         if (currentFolderFSEntry.FullName == MWFVFS.MyComputerPrefix) {
3227                                 directories_out.AddRange (GetMyComputerContent ());
3228                         } else
3229                         if (currentFolderFSEntry.FullName == MWFVFS.PersonalPrefix || currentFolderFSEntry.FullName == MWFVFS.MyComputerPersonalPrefix) {
3230                                 ArrayList d_out = GetNormalFolders (ThemeEngine.Current.Places (UIIcon.PlacesPersonal));
3231                                 directories_out.AddRange (d_out);
3232                         } else
3233                         if (currentFolderFSEntry.FullName == MWFVFS.MyNetworkPrefix) {
3234                                 directories_out.AddRange (GetMyNetworkContent ());
3235                         } else {
3236                                 directories_out = GetNormalFolders (currentFolderFSEntry.FullName);
3237                         }
3238                         return directories_out;
3239                 }
3240                 
3241                 protected void GetNormalFolderContent (string from_folder, StringCollection filters, out ArrayList directories_out, out ArrayList files_out)
3242                 {
3243                         DirectoryInfo dirinfo = new DirectoryInfo (from_folder);
3244                         
3245                         directories_out = new ArrayList ();
3246                         
3247                         DirectoryInfo[] dirs = null;
3248                         
3249                         try {
3250                                 dirs = dirinfo.GetDirectories ();
3251                         } catch (Exception) {}
3252                         
3253                         if (dirs != null)
3254                                 for (int i = 0; i < dirs.Length; i++) {
3255                                         directories_out.Add (GetDirectoryFSEntry (dirs [i], currentTopFolderFSEntry));
3256                                 }
3257                         
3258                         files_out = new ArrayList ();
3259                         
3260                         ArrayList files = new ArrayList ();
3261                         
3262                         try {
3263                                 if (filters == null) {
3264                                         files.AddRange (dirinfo.GetFiles ());
3265                                 } else {
3266                                         foreach (string s in filters)
3267                                                 files.AddRange (dirinfo.GetFiles (s));
3268                                         
3269                                         files.Sort (fileInfoComparer);
3270                                 }
3271                         } catch (Exception) {}
3272                         
3273                         for (int i = 0; i < files.Count; i++) {
3274                                 FSEntry fs = GetFileFSEntry (files [i] as FileInfo);
3275                                 if (fs != null)
3276                                         files_out.Add (fs);
3277                         }
3278                 }
3279                 
3280                 protected ArrayList GetNormalFolders (string from_folder)
3281                 {
3282                         DirectoryInfo dirinfo = new DirectoryInfo (from_folder);
3283                         
3284                         ArrayList directories_out = new ArrayList ();
3285                         
3286                         DirectoryInfo[] dirs = null;
3287                         
3288                         try {
3289                                 dirs = dirinfo.GetDirectories ();
3290                         } catch (Exception) {}
3291                         
3292                         if (dirs != null)
3293                                 for (int i = 0; i < dirs.Length; i++) {
3294                                         directories_out.Add (GetDirectoryFSEntry (dirs [i], currentTopFolderFSEntry));
3295                                 }
3296                         
3297                         return directories_out;
3298                 }
3299                 
3300                 protected virtual FSEntry GetDirectoryFSEntry (DirectoryInfo dirinfo, FSEntry topFolderFSEntry)
3301                 {
3302                         FSEntry fs = new FSEntry ();
3303                         
3304                         fs.Attributes = dirinfo.Attributes;
3305                         fs.FullName = dirinfo.FullName;
3306                         fs.Name = dirinfo.Name;
3307                         fs.MainTopNode = topFolderFSEntry;
3308                         fs.FileType = FSEntry.FSEntryType.Directory;
3309                         fs.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("inode/directory");
3310                         fs.LastAccessTime = dirinfo.LastAccessTime;
3311                         
3312                         return fs;
3313                 }
3314                 
3315                 protected virtual FSEntry GetFileFSEntry (FileInfo fileinfo)
3316                 {
3317                         // *sigh* FileInfo gives us no usable information for links to directories
3318                         // so, return null
3319                         if ((fileinfo.Attributes & FileAttributes.Directory) == FileAttributes.Directory)
3320                                 return null;
3321                         
3322                         FSEntry fs = new FSEntry ();
3323                         
3324                         fs.Attributes = fileinfo.Attributes;
3325                         fs.FullName = fileinfo.FullName;
3326                         fs.Name = fileinfo.Name;
3327                         fs.FileType = FSEntry.FSEntryType.File;
3328                         fs.IconIndex = MimeIconEngine.GetIconIndexForFile (fileinfo.FullName);
3329                         fs.FileSize = fileinfo.Length;
3330                         fs.LastAccessTime = fileinfo.LastAccessTime;
3331                         
3332                         return fs;
3333                 }
3334                 
3335                 internal class FileInfoComparer : IComparer
3336                 {
3337                         public int Compare (object fileInfo1, object fileInfo2)
3338                         {
3339                                 return String.Compare (((FileInfo)fileInfo1).Name, ((FileInfo)fileInfo2).Name);
3340                         }
3341                 }
3342                 
3343                 protected abstract FSEntry GetDesktopFSEntry ();
3344                 
3345                 protected abstract FSEntry GetRecentlyUsedFSEntry ();
3346                 
3347                 protected abstract FSEntry GetPersonalFSEntry ();
3348                 
3349                 protected abstract FSEntry GetMyComputerPersonalFSEntry ();
3350                 
3351                 protected abstract FSEntry GetMyComputerFSEntry ();
3352                 
3353                 protected abstract FSEntry GetMyNetworkFSEntry ();
3354                 
3355                 public abstract void WriteRecentlyUsedFiles (string fileToAdd);
3356                 
3357                 public abstract ArrayList GetRecentlyUsedFiles ();
3358                 
3359                 public abstract ArrayList GetMyComputerContent ();
3360                 
3361                 public abstract ArrayList GetMyNetworkContent ();
3362         }
3363         #endregion
3364         
3365         #region UnixFileSystem
3366         internal class UnixFileSystem : FileSystem
3367         {
3368                 private MasterMount masterMount = new MasterMount ();
3369                 private FSEntry desktopFSEntry = null;
3370                 private FSEntry recentlyusedFSEntry = null;
3371                 private FSEntry personalFSEntry = null;
3372                 private FSEntry mycomputerpersonalFSEntry = null;
3373                 private FSEntry mycomputerFSEntry = null;
3374                 private FSEntry mynetworkFSEntry = null;
3375                 
3376                 private string personal_folder;
3377                 private string recently_used_path;
3378                 private string full_kde_recent_document_dir;
3379                 
3380                 public UnixFileSystem ()
3381                 {
3382                         personal_folder = ThemeEngine.Current.Places (UIIcon.PlacesPersonal);
3383                         recently_used_path = Path.Combine (personal_folder, ".recently-used");
3384                         
3385                         full_kde_recent_document_dir = personal_folder + "/.kde/share/apps/RecentDocuments";
3386                         
3387                         desktopFSEntry = new FSEntry ();
3388                         
3389                         desktopFSEntry.Attributes = FileAttributes.Directory;
3390                         desktopFSEntry.FullName = MWFVFS.DesktopPrefix;
3391                         desktopFSEntry.Name = "Desktop";
3392                         desktopFSEntry.RealName = ThemeEngine.Current.Places (UIIcon.PlacesDesktop);
3393                         desktopFSEntry.FileType = FSEntry.FSEntryType.Directory;
3394                         desktopFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("desktop/desktop");
3395                         desktopFSEntry.LastAccessTime = DateTime.Now;
3396                         
3397                         recentlyusedFSEntry = new FSEntry ();
3398                         
3399                         recentlyusedFSEntry.Attributes = FileAttributes.Directory;
3400                         recentlyusedFSEntry.FullName = MWFVFS.RecentlyUsedPrefix;
3401                         recentlyusedFSEntry.Name = "Recently Used";
3402                         recentlyusedFSEntry.FileType = FSEntry.FSEntryType.Directory;
3403                         recentlyusedFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("recently/recently");
3404                         recentlyusedFSEntry.LastAccessTime = DateTime.Now;
3405                         
3406                         personalFSEntry = new FSEntry ();
3407                         
3408                         personalFSEntry.Attributes = FileAttributes.Directory;
3409                         personalFSEntry.FullName = MWFVFS.PersonalPrefix;
3410                         personalFSEntry.Name = "Personal";
3411                         personalFSEntry.MainTopNode = GetDesktopFSEntry ();
3412                         personalFSEntry.RealName = ThemeEngine.Current.Places (UIIcon.PlacesPersonal);
3413                         personalFSEntry.FileType = FSEntry.FSEntryType.Directory;
3414                         personalFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("directory/home");
3415                         personalFSEntry.LastAccessTime = DateTime.Now;
3416                         
3417                         mycomputerpersonalFSEntry = new FSEntry ();
3418                         
3419                         mycomputerpersonalFSEntry.Attributes = FileAttributes.Directory;
3420                         mycomputerpersonalFSEntry.FullName = MWFVFS.MyComputerPersonalPrefix;
3421                         mycomputerpersonalFSEntry.Name = "Personal";
3422                         mycomputerpersonalFSEntry.MainTopNode = GetMyComputerFSEntry ();
3423                         mycomputerpersonalFSEntry.RealName = ThemeEngine.Current.Places (UIIcon.PlacesPersonal);
3424                         mycomputerpersonalFSEntry.FileType = FSEntry.FSEntryType.Directory;
3425                         mycomputerpersonalFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("directory/home");
3426                         mycomputerpersonalFSEntry.LastAccessTime = DateTime.Now;
3427                         
3428                         mycomputerFSEntry = new FSEntry ();
3429                         
3430                         mycomputerFSEntry.Attributes = FileAttributes.Directory;
3431                         mycomputerFSEntry.FullName = MWFVFS.MyComputerPrefix;
3432                         mycomputerFSEntry.Name = "My Computer";
3433                         mycomputerFSEntry.MainTopNode = GetDesktopFSEntry ();
3434                         mycomputerFSEntry.FileType = FSEntry.FSEntryType.Directory;
3435                         mycomputerFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("workplace/workplace");
3436                         mycomputerFSEntry.LastAccessTime = DateTime.Now;
3437                         
3438                         mynetworkFSEntry = new FSEntry ();
3439                         
3440                         mynetworkFSEntry.Attributes = FileAttributes.Directory;
3441                         mynetworkFSEntry.FullName = MWFVFS.MyNetworkPrefix;
3442                         mynetworkFSEntry.Name = "My Network";
3443                         mynetworkFSEntry.MainTopNode = GetDesktopFSEntry ();
3444                         mynetworkFSEntry.FileType = FSEntry.FSEntryType.Directory;
3445                         mynetworkFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("network/network");
3446                         mynetworkFSEntry.LastAccessTime = DateTime.Now;
3447                 }
3448                 
3449                 public override void WriteRecentlyUsedFiles (string fileToAdd)
3450                 {
3451                         if (File.Exists (recently_used_path) && new FileInfo (recently_used_path).Length > 0) {
3452                                 XmlDocument xml_doc = new XmlDocument ();
3453                                 xml_doc.Load (recently_used_path);
3454                                 
3455                                 XmlNode grand_parent_node = xml_doc.SelectSingleNode ("RecentFiles");
3456                                 
3457                                 if (grand_parent_node != null) {
3458                                         // create a new element
3459                                         XmlElement new_recent_item_node = xml_doc.CreateElement ("RecentItem");
3460                                         
3461                                         XmlElement new_child = xml_doc.CreateElement ("URI");
3462                                         UriBuilder ub = new UriBuilder ();
3463                                         ub.Path = fileToAdd;
3464                                         ub.Host = null;
3465                                         ub.Scheme = "file";
3466                                         XmlText new_text_child = xml_doc.CreateTextNode (ub.ToString ());
3467                                         new_child.AppendChild (new_text_child);
3468                                         
3469                                         new_recent_item_node.AppendChild (new_child);
3470                                         
3471                                         new_child = xml_doc.CreateElement ("Mime-Type");
3472                                         new_text_child = xml_doc.CreateTextNode (Mime.GetMimeTypeForFile (fileToAdd));
3473                                         new_child.AppendChild (new_text_child);
3474                                         
3475                                         new_recent_item_node.AppendChild (new_child);
3476                                         
3477                                         new_child = xml_doc.CreateElement ("Timestamp");
3478                                         long seconds = (long)(DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalSeconds;
3479                                         new_text_child = xml_doc.CreateTextNode (seconds.ToString ());
3480                                         new_child.AppendChild (new_text_child);
3481                                         
3482                                         new_recent_item_node.AppendChild (new_child);
3483                                         
3484                                         new_child = xml_doc.CreateElement ("Groups");
3485                                         
3486                                         new_recent_item_node.AppendChild (new_child);
3487                                         
3488                                         // now search the nodes in grand_parent_node for another instance of the new uri and if found remove it
3489                                         // so that the new node is the first one
3490                                         foreach (XmlNode n in grand_parent_node.ChildNodes) {
3491                                                 XmlNode uri_node = n.SelectSingleNode ("URI");
3492                                                 if (uri_node != null) {
3493                                                         XmlNode uri_node_child = uri_node.FirstChild;
3494                                                         if (uri_node_child is XmlText)
3495                                                                 if (ub.ToString () == ((XmlText)uri_node_child).Data) {
3496                                                                         grand_parent_node.RemoveChild (n);
3497                                                                         break;
3498                                                                 }
3499                                                 }
3500                                         }
3501                                         
3502                                         // prepend the new recent item to the grand parent node list
3503                                         grand_parent_node.PrependChild (new_recent_item_node);
3504                                         
3505                                         // limit the # of RecentItems to 10
3506                                         if (grand_parent_node.ChildNodes.Count > 10) {
3507                                                 while (grand_parent_node.ChildNodes.Count > 10)
3508                                                         grand_parent_node.RemoveChild (grand_parent_node.LastChild);
3509                                         }
3510                                         
3511                                         try {
3512                                                 xml_doc.Save (recently_used_path);
3513                                         } catch (Exception) {
3514                                         }
3515                                 }
3516                         } else {
3517                                 XmlDocument xml_doc = new XmlDocument ();
3518                                 xml_doc.AppendChild (xml_doc.CreateXmlDeclaration ("1.0", String.Empty, String.Empty));
3519                                 
3520                                 XmlElement recentFiles_element = xml_doc.CreateElement ("RecentFiles");
3521                                 
3522                                 XmlElement new_recent_item_node = xml_doc.CreateElement ("RecentItem");
3523                                 
3524                                 XmlElement new_child = xml_doc.CreateElement ("URI");
3525                                 UriBuilder ub = new UriBuilder ();
3526                                 ub.Path = fileToAdd;
3527                                 ub.Host = null;
3528                                 ub.Scheme = "file";
3529                                 XmlText new_text_child = xml_doc.CreateTextNode (ub.ToString ());
3530                                 new_child.AppendChild (new_text_child);
3531                                 
3532                                 new_recent_item_node.AppendChild (new_child);
3533                                 
3534                                 new_child = xml_doc.CreateElement ("Mime-Type");
3535                                 new_text_child = xml_doc.CreateTextNode (Mime.GetMimeTypeForFile (fileToAdd));
3536                                 new_child.AppendChild (new_text_child);
3537                                 
3538                                 new_recent_item_node.AppendChild (new_child);
3539                                 
3540                                 new_child = xml_doc.CreateElement ("Timestamp");
3541                                 long seconds = (long)(DateTime.UtcNow - new DateTime (1970, 1, 1)).TotalSeconds;
3542                                 new_text_child = xml_doc.CreateTextNode (seconds.ToString ());
3543                                 new_child.AppendChild (new_text_child);
3544                                 
3545                                 new_recent_item_node.AppendChild (new_child);
3546                                 
3547                                 new_child = xml_doc.CreateElement ("Groups");
3548                                 
3549                                 new_recent_item_node.AppendChild (new_child);
3550                                 
3551                                 recentFiles_element.AppendChild (new_recent_item_node);
3552                                 
3553                                 xml_doc.AppendChild (recentFiles_element);
3554                                 
3555                                 try {
3556                                         xml_doc.Save (recently_used_path);
3557                                 } catch (Exception) {
3558                                 }
3559                         }
3560                 }
3561                 
3562                 // return an ArrayList with FSEntry objects
3563                 public override ArrayList GetRecentlyUsedFiles ()
3564                 {
3565                         // check for GNOME and KDE
3566                         
3567                         ArrayList files_al = new ArrayList ();
3568                         
3569                         // GNOME
3570                         if (File.Exists (recently_used_path)) {
3571                                 try {
3572                                         XmlTextReader xtr = new XmlTextReader (recently_used_path);
3573                                         while (xtr.Read ()) {
3574                                                 if (xtr.NodeType == XmlNodeType.Element && xtr.Name.ToUpper () == "URI") {
3575                                                         xtr.Read ();
3576                                                         Uri uri = new Uri (xtr.Value);
3577                                                         if (!files_al.Contains (uri.LocalPath))
3578                                                                 if (File.Exists (uri.LocalPath)) {
3579                                                                         FSEntry fs = GetFileFSEntry (new FileInfo (uri.LocalPath));
3580                                                                         if (fs != null)
3581                                                                                 files_al.Add (fs);
3582                                                                 }
3583                                                 }
3584                                         }
3585                                         xtr.Close ();
3586                                 } catch (Exception) {
3587                                         
3588                                 }
3589                         }
3590                         
3591                         // KDE
3592                         if (Directory.Exists (full_kde_recent_document_dir)) {
3593                                 string[] files = Directory.GetFiles (full_kde_recent_document_dir, "*.desktop");
3594                                 
3595                                 foreach (string file_name in files) {
3596                                         StreamReader sr = new StreamReader (file_name);
3597                                         
3598                                         string line = sr.ReadLine ();
3599                                         
3600                                         while (line != null) {
3601                                                 line = line.Trim ();
3602                                                 
3603                                                 if (line.StartsWith ("URL=")) {
3604                                                         line = line.Replace ("URL=", String.Empty);
3605                                                         line = line.Replace ("$HOME", personal_folder);
3606                                                         
3607                                                         Uri uri = new Uri (line);
3608                                                         if (!files_al.Contains (uri.LocalPath))
3609                                                                 if (File.Exists (uri.LocalPath)) {
3610                                                                         FSEntry fs = GetFileFSEntry (new FileInfo (uri.LocalPath));
3611                                                                         if (fs != null)
3612                                                                                 files_al.Add (fs);
3613                                                                 }
3614                                                         break;
3615                                                 }
3616                                                 
3617                                                 line = sr.ReadLine ();
3618                                         }
3619                                         
3620                                         sr.Close ();
3621                                 }
3622                         }
3623                         
3624                         
3625                         return files_al;
3626                 }
3627                 
3628                 // return an ArrayList with FSEntry objects
3629                 public override ArrayList GetMyComputerContent ()
3630                 {
3631                         ArrayList my_computer_content_arraylist = new ArrayList ();
3632                         
3633                         if (masterMount.ProcMountAvailable) {
3634                                 masterMount.GetMounts ();
3635                                 
3636                                 foreach (MasterMount.Mount mount in masterMount.Block_devices) {
3637                                         FSEntry fsEntry = new FSEntry ();
3638                                         fsEntry.FileType = FSEntry.FSEntryType.Device;
3639                                         
3640                                         fsEntry.FullName = mount.mount_point;
3641                                         
3642                                         fsEntry.Name = "HDD (" +  mount.fsType + ", " + mount.device_short + ")";
3643                                         
3644                                         fsEntry.FsType = mount.fsType;
3645                                         fsEntry.DeviceShort = mount.device_short;
3646                                         
3647                                         fsEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("harddisk/harddisk");
3648                                         
3649                                         fsEntry.Attributes = FileAttributes.Directory;
3650                                         
3651                                         fsEntry.MainTopNode = GetMyComputerFSEntry ();
3652                                         
3653                                         my_computer_content_arraylist.Add (fsEntry);
3654                                         
3655                                         if (!MWFVFS.MyComputerDevicesPrefix.Contains (fsEntry.FullName + "://"))
3656                                                 MWFVFS.MyComputerDevicesPrefix.Add (fsEntry.FullName + "://", fsEntry);
3657                                 }
3658                                 
3659                                 foreach (MasterMount.Mount mount in masterMount.Removable_devices) {
3660                                         FSEntry fsEntry = new FSEntry ();
3661                                         fsEntry.FileType = FSEntry.FSEntryType.RemovableDevice;
3662                                         
3663                                         fsEntry.FullName = mount.mount_point;
3664                                         
3665                                         bool is_dvd_cdrom = mount.fsType == MasterMount.FsTypes.usbfs ? false : true;
3666                                         string type_name = is_dvd_cdrom ? "DVD/CD-Rom" : "USB";
3667                                         string mime_type = is_dvd_cdrom ? "cdrom/cdrom" : "removable/removable";
3668                                         
3669                                         fsEntry.Name = type_name +" (" + mount.device_short + ")";
3670                                         
3671                                         fsEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType (mime_type);
3672                                         
3673                                         fsEntry.FsType = mount.fsType;
3674                                         fsEntry.DeviceShort = mount.device_short;
3675                                         
3676                                         fsEntry.Attributes = FileAttributes.Directory;
3677                                         
3678                                         fsEntry.MainTopNode = GetMyComputerFSEntry ();
3679                                         
3680                                         my_computer_content_arraylist.Add (fsEntry);
3681                                         
3682                                         string contain_string = fsEntry.FullName + "://";
3683                                         if (!MWFVFS.MyComputerDevicesPrefix.Contains (contain_string))
3684                                                 MWFVFS.MyComputerDevicesPrefix.Add (contain_string, fsEntry);
3685                                 }
3686                         }
3687                         
3688                         my_computer_content_arraylist.Add (GetMyComputerPersonalFSEntry ());
3689                         
3690                         return my_computer_content_arraylist;
3691                 }
3692                 
3693                 public override ArrayList GetMyNetworkContent ()
3694                 {
3695                         ArrayList fsEntries = new ArrayList ();
3696                         
3697                         foreach (MasterMount.Mount mount in masterMount.Network_devices) {
3698                                 FSEntry fsEntry = new FSEntry ();
3699                                 fsEntry.FileType = FSEntry.FSEntryType.Network;
3700                                 
3701                                 fsEntry.FullName = mount.mount_point;
3702                                 
3703                                 fsEntry.FsType = mount.fsType;
3704                                 fsEntry.DeviceShort = mount.device_short;
3705                                 
3706                                 fsEntry.Name = "Network (" + mount.fsType + ", " + mount.device_short + ")";
3707                                 
3708                                 switch (mount.fsType) {
3709                                         case MasterMount.FsTypes.nfs:
3710                                                 fsEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("nfs/nfs");
3711                                                 break;
3712                                         case MasterMount.FsTypes.smbfs:
3713                                                 fsEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("smb/smb");
3714                                                 break;
3715                                         case MasterMount.FsTypes.ncpfs:
3716                                                 fsEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("network/network");
3717                                                 break;
3718                                         case MasterMount.FsTypes.cifs:
3719                                                 fsEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("network/network");
3720                                                 break;
3721                                         default:
3722                                                 break;
3723                                 }
3724                                 
3725                                 fsEntry.Attributes = FileAttributes.Directory;
3726                                 
3727                                 fsEntry.MainTopNode = GetMyNetworkFSEntry ();
3728                                 
3729                                 fsEntries.Add (fsEntry);
3730                         }
3731                         return fsEntries;
3732                 }
3733                 
3734                 protected override FSEntry GetDesktopFSEntry ()
3735                 {
3736                         return desktopFSEntry;
3737                 }
3738                 
3739                 protected override FSEntry GetRecentlyUsedFSEntry ()
3740                 {
3741                         return recentlyusedFSEntry;
3742                 }
3743                 
3744                 protected override FSEntry GetPersonalFSEntry ()
3745                 {
3746                         return personalFSEntry;
3747                 }
3748                 
3749                 protected override FSEntry GetMyComputerPersonalFSEntry ()
3750                 {
3751                         return mycomputerpersonalFSEntry;
3752                 }
3753                 
3754                 protected override FSEntry GetMyComputerFSEntry ()
3755                 {
3756                         return mycomputerFSEntry;
3757                 }
3758                 
3759                 protected override FSEntry GetMyNetworkFSEntry ()
3760                 {
3761                         return mynetworkFSEntry;
3762                 }
3763         }
3764         #endregion
3765         
3766         #region WinFileSystem
3767         internal class WinFileSystem : FileSystem
3768         {
3769                 private FSEntry desktopFSEntry = null;
3770                 private FSEntry recentlyusedFSEntry = null;
3771                 private FSEntry personalFSEntry = null;
3772                 private FSEntry mycomputerpersonalFSEntry = null;
3773                 private FSEntry mycomputerFSEntry = null;
3774                 private FSEntry mynetworkFSEntry = null;
3775                 
3776                 public WinFileSystem ()
3777                 {
3778                         desktopFSEntry = new FSEntry ();
3779                         
3780                         desktopFSEntry.Attributes = FileAttributes.Directory;
3781                         desktopFSEntry.FullName = MWFVFS.DesktopPrefix;
3782                         desktopFSEntry.Name = "Desktop";
3783                         desktopFSEntry.RealName = ThemeEngine.Current.Places (UIIcon.PlacesDesktop);
3784                         desktopFSEntry.FileType = FSEntry.FSEntryType.Directory;
3785                         desktopFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("desktop/desktop");
3786                         desktopFSEntry.LastAccessTime = DateTime.Now;
3787                         
3788                         recentlyusedFSEntry = new FSEntry ();
3789                         
3790                         recentlyusedFSEntry.Attributes = FileAttributes.Directory;
3791                         recentlyusedFSEntry.FullName = MWFVFS.RecentlyUsedPrefix;
3792                         recentlyusedFSEntry.RealName = ThemeEngine.Current.Places (UIIcon.PlacesRecentDocuments);
3793                         recentlyusedFSEntry.Name = "Recently Used";
3794                         recentlyusedFSEntry.FileType = FSEntry.FSEntryType.Directory;
3795                         recentlyusedFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("recently/recently");
3796                         recentlyusedFSEntry.LastAccessTime = DateTime.Now;
3797                         
3798                         personalFSEntry = new FSEntry ();
3799                         
3800                         personalFSEntry.Attributes = FileAttributes.Directory;
3801                         personalFSEntry.FullName = MWFVFS.PersonalPrefix;
3802                         personalFSEntry.Name = "Personal";
3803                         personalFSEntry.MainTopNode = GetDesktopFSEntry ();
3804                         personalFSEntry.RealName = ThemeEngine.Current.Places (UIIcon.PlacesPersonal);
3805                         personalFSEntry.FileType = FSEntry.FSEntryType.Directory;
3806                         personalFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("directory/home");
3807                         personalFSEntry.LastAccessTime = DateTime.Now;
3808                         
3809                         mycomputerpersonalFSEntry = new FSEntry ();
3810                         
3811                         mycomputerpersonalFSEntry.Attributes = FileAttributes.Directory;
3812                         mycomputerpersonalFSEntry.FullName = MWFVFS.MyComputerPersonalPrefix;
3813                         mycomputerpersonalFSEntry.Name = "Personal";
3814                         mycomputerpersonalFSEntry.MainTopNode = GetMyComputerFSEntry ();
3815                         mycomputerpersonalFSEntry.RealName = ThemeEngine.Current.Places (UIIcon.PlacesPersonal);
3816                         mycomputerpersonalFSEntry.FileType = FSEntry.FSEntryType.Directory;
3817                         mycomputerpersonalFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("directory/home");
3818                         mycomputerpersonalFSEntry.LastAccessTime = DateTime.Now;
3819                         
3820                         mycomputerFSEntry = new FSEntry ();
3821                         
3822                         mycomputerFSEntry.Attributes = FileAttributes.Directory;
3823                         mycomputerFSEntry.FullName = MWFVFS.MyComputerPrefix;
3824                         mycomputerFSEntry.Name = "My Computer";
3825                         mycomputerFSEntry.MainTopNode = GetDesktopFSEntry ();
3826                         mycomputerFSEntry.FileType = FSEntry.FSEntryType.Directory;
3827                         mycomputerFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("workplace/workplace");
3828                         mycomputerFSEntry.LastAccessTime = DateTime.Now;
3829                         
3830                         mynetworkFSEntry = new FSEntry ();
3831                         
3832                         mynetworkFSEntry.Attributes = FileAttributes.Directory;
3833                         mynetworkFSEntry.FullName = MWFVFS.MyNetworkPrefix;
3834                         mynetworkFSEntry.Name = "My Network";
3835                         mynetworkFSEntry.MainTopNode = GetDesktopFSEntry ();
3836                         mynetworkFSEntry.FileType = FSEntry.FSEntryType.Directory;
3837                         mynetworkFSEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("network/network");
3838                         mynetworkFSEntry.LastAccessTime = DateTime.Now;
3839                 }
3840                 
3841                 public override void WriteRecentlyUsedFiles (string fileToAdd)
3842                 {
3843                         // TODO: Implement this method
3844                         // use SHAddToRecentDocs ?
3845                 }
3846                 
3847                 public override ArrayList GetRecentlyUsedFiles ()
3848                 {
3849                         ArrayList al = new ArrayList ();
3850                         
3851                         DirectoryInfo di = new DirectoryInfo (recentlyusedFSEntry.RealName);
3852                         
3853                         FileInfo[] fileinfos = di.GetFiles ();
3854                         
3855                         foreach (FileInfo fi in fileinfos) {
3856                                 FSEntry fs = GetFileFSEntry (fi);
3857                                 if (fs != null)
3858                                         al.Add (fs);
3859                         }
3860                         
3861                         return al;
3862                 }
3863                 
3864                 public override ArrayList GetMyComputerContent ()
3865                 {
3866                         string[] logical_drives = Directory.GetLogicalDrives ();
3867                         
3868                         ArrayList my_computer_content_arraylist = new ArrayList ();
3869                         
3870                         foreach (string drive in logical_drives) {
3871                                 FSEntry fsEntry = new FSEntry ();
3872                                 fsEntry.FileType = FSEntry.FSEntryType.Device;
3873                                 
3874                                 fsEntry.FullName = drive;
3875                                 
3876                                 fsEntry.Name = drive;
3877                                 
3878                                 fsEntry.IconIndex = MimeIconEngine.GetIconIndexForMimeType ("harddisk/harddisk");
3879                                 
3880                                 fsEntry.Attributes = FileAttributes.Directory;
3881                                 
3882                                 fsEntry.MainTopNode = GetMyComputerFSEntry ();
3883                                 
3884                                 my_computer_content_arraylist.Add (fsEntry);
3885                                 
3886                                 string contain_string = fsEntry.FullName + "://";
3887                                 if (!MWFVFS.MyComputerDevicesPrefix.Contains (contain_string))
3888                                         MWFVFS.MyComputerDevicesPrefix.Add (contain_string, fsEntry);
3889                         }
3890                         
3891                         my_computer_content_arraylist.Add (GetMyComputerPersonalFSEntry ());
3892                         
3893                         return my_computer_content_arraylist;
3894                 }
3895                 
3896                 public override ArrayList GetMyNetworkContent ()
3897                 {
3898                         // TODO: Implement this method
3899                         return new ArrayList ();
3900                 }
3901                 protected override FSEntry GetDesktopFSEntry ()
3902                 {
3903                         return desktopFSEntry;
3904                 }
3905                 
3906                 protected override FSEntry GetRecentlyUsedFSEntry ()
3907                 {
3908                         return recentlyusedFSEntry;
3909                 }
3910                 
3911                 protected override FSEntry GetPersonalFSEntry ()
3912                 {
3913                         return personalFSEntry;
3914                 }
3915                 
3916                 protected override FSEntry GetMyComputerPersonalFSEntry ()
3917                 {
3918                         return mycomputerpersonalFSEntry;
3919                 }
3920                 
3921                 protected override FSEntry GetMyComputerFSEntry ()
3922                 {
3923                         return mycomputerFSEntry;
3924                 }
3925                 
3926                 protected override FSEntry GetMyNetworkFSEntry ()
3927                 {
3928                         return mynetworkFSEntry;
3929                 }
3930         }
3931         #endregion
3932         
3933         #region FSEntry
3934         internal class FSEntry
3935         {
3936                 public enum FSEntryType
3937                 {
3938                         Desktop,
3939                         RecentlyUsed,
3940                         MyComputer,
3941                         File,
3942                         Directory,
3943                         Device,
3944                         RemovableDevice,
3945                         Network
3946                 }
3947                 
3948                 private MasterMount.FsTypes fsType;
3949                 private string device_short;
3950                 private string fullName;
3951                 private string name;
3952                 private string realName = null;
3953                 private FileAttributes attributes = FileAttributes.Normal;
3954                 private long fileSize;
3955                 private FSEntryType fileType;
3956                 private DateTime lastAccessTime;
3957                 private FSEntry mainTopNode = null;
3958                 
3959                 private int iconIndex;
3960                 
3961                 private string parent;
3962                 
3963                 public MasterMount.FsTypes FsType {
3964                         set {
3965                                 fsType = value;
3966                         }
3967                         
3968                         get {
3969                                 return fsType;
3970                         }
3971                 }
3972                 
3973                 public string DeviceShort {
3974                         set {
3975                                 device_short = value;
3976                         }
3977                         
3978                         get {
3979                                 return device_short;
3980                         }
3981                 }
3982                 
3983                 public string FullName {
3984                         set {
3985                                 fullName = value;
3986                         }
3987                         
3988                         get {
3989                                 return fullName;
3990                         }
3991                 }
3992                 
3993                 public string Name {
3994                         set {
3995                                 name = value;
3996                         }
3997                         
3998                         get {
3999                                 return name;
4000                         }
4001                 }
4002                 
4003                 public string RealName {
4004                         set {
4005                                 realName = value;
4006                         }
4007                         
4008                         get {
4009                                 return realName;
4010                         }
4011                 }
4012                 
4013                 public FileAttributes Attributes {
4014                         set {
4015                                 attributes = value;
4016                         }
4017                         
4018                         get {
4019                                 return attributes;
4020                         }
4021                 }
4022                 
4023                 public long FileSize {
4024                         set {
4025                                 fileSize = value;
4026                         }
4027                         
4028                         get {
4029                                 return fileSize;
4030                         }
4031                 }
4032                 
4033                 public FSEntryType FileType {
4034                         set {
4035                                 fileType = value;
4036                         }
4037                         
4038                         get {
4039                                 return fileType;
4040                         }
4041                 }
4042                 
4043                 public DateTime LastAccessTime {
4044                         set {
4045                                 lastAccessTime = value;
4046                         }
4047                         
4048                         get {
4049                                 return lastAccessTime;
4050                         }
4051                 }
4052                 
4053                 public int IconIndex {
4054                         set {
4055                                 iconIndex = value;
4056                         }
4057                         
4058                         get {
4059                                 return iconIndex;
4060                         }
4061                 }
4062                 
4063                 public FSEntry MainTopNode {
4064                         set {
4065                                 mainTopNode = value;
4066                         }
4067                         
4068                         get {
4069                                 return mainTopNode;
4070                         }
4071                 }
4072                 
4073                 public string Parent {
4074                         set {
4075                                 parent = value;
4076                         }
4077                         
4078                         get {
4079                                 parent = GetParent ();
4080                                 
4081                                 return parent;
4082                         }
4083                 }
4084                 
4085                 private string GetParent ()
4086                 {
4087                         if (fullName == MWFVFS.PersonalPrefix) {
4088                                 return MWFVFS.DesktopPrefix;
4089                         } else
4090                         if (fullName == MWFVFS.MyComputerPersonalPrefix) {
4091                                 return MWFVFS.MyComputerPrefix;
4092                         } else
4093                         if (fullName == MWFVFS.MyComputerPrefix) {
4094                                 return MWFVFS.DesktopPrefix;
4095                         } else
4096                         if (fullName == MWFVFS.MyNetworkPrefix) {
4097                                 return MWFVFS.DesktopPrefix;
4098                         } else
4099                         if (fullName == MWFVFS.DesktopPrefix) {
4100                                 return null;
4101                         } else
4102                         if (fullName == MWFVFS.RecentlyUsedPrefix) {
4103                                 return null;
4104                         } else {
4105                                 foreach (DictionaryEntry entry in MWFVFS.MyComputerDevicesPrefix) {
4106                                         FSEntry fsEntry = entry.Value as FSEntry;
4107                                         if (fullName == fsEntry.FullName) {
4108                                                 return fsEntry.MainTopNode.FullName;
4109                                         }
4110                                 }
4111                                 
4112                                 DirectoryInfo dirInfo = new DirectoryInfo (fullName);
4113                                 
4114                                 DirectoryInfo dirInfoParent = dirInfo.Parent;
4115                                 
4116                                 if (dirInfoParent != null) {
4117                                         FSEntry fsEntry = MWFVFS.MyComputerDevicesPrefix [dirInfoParent.FullName + "://"] as FSEntry;
4118                                         
4119                                         if (fsEntry != null) {
4120                                                 return fsEntry.FullName;
4121                                         }
4122                                         
4123                                         if (mainTopNode != null) {
4124                                                 if (dirInfoParent.FullName == ThemeEngine.Current.Places (UIIcon.PlacesDesktop) &&
4125                                                     mainTopNode.FullName == MWFVFS.DesktopPrefix) {
4126                                                         return mainTopNode.FullName;
4127                                                 } else
4128                                                 if (dirInfoParent.FullName == ThemeEngine.Current.Places (UIIcon.PlacesPersonal) &&
4129                                                     mainTopNode.FullName == MWFVFS.PersonalPrefix) {
4130                                                         return mainTopNode.FullName;
4131                                                 } else
4132                                                 if (dirInfoParent.FullName == ThemeEngine.Current.Places (UIIcon.PlacesPersonal) &&
4133                                                     mainTopNode.FullName == MWFVFS.MyComputerPersonalPrefix) {
4134                                                         return mainTopNode.FullName;
4135                                                 }
4136                                         }
4137                                         
4138                                         return dirInfoParent.FullName;
4139                                 }
4140                         }
4141                         
4142                         return null;
4143                 }
4144         }
4145         #endregion
4146         
4147         #region MasterMount
4148         // Alexsantas little *nix helper
4149         internal class MasterMount
4150         {
4151                 // add more...
4152                 internal enum FsTypes
4153                 {
4154                         none,
4155                         ext2,
4156                         ext3,
4157                         hpfs,
4158                         iso9660,
4159                         jfs,
4160                         minix,
4161                         msdos,
4162                         ntfs,
4163                         reiserfs,
4164                         ufs,
4165                         umsdos,
4166                         vfat,
4167                         sysv,
4168                         xfs,
4169                         ncpfs,
4170                         nfs,
4171                         smbfs,
4172                         usbfs,
4173                         cifs
4174                 }
4175                 
4176                 internal struct Mount
4177                 {
4178                         public string device_or_filesystem;
4179                         public string device_short;
4180                         public string mount_point;
4181                         public FsTypes fsType;
4182                 }
4183                 
4184                 bool proc_mount_available = false;
4185                 
4186                 ArrayList block_devices = new ArrayList ();
4187                 ArrayList network_devices = new ArrayList ();
4188                 ArrayList removable_devices = new ArrayList ();
4189                 
4190                 private int platform = (int) Environment.OSVersion.Platform;
4191                 private MountComparer mountComparer = new MountComparer ();
4192                 
4193                 public MasterMount ()
4194                 {
4195                         // maybe check if the current user can access /proc/mounts
4196                         if ((platform == 4) || (platform == 128))
4197                                 if (File.Exists ("/proc/mounts"))
4198                                         proc_mount_available = true;
4199                 }
4200                 
4201                 public ArrayList Block_devices {
4202                         get {
4203                                 return block_devices;
4204                         }
4205                 }
4206                 
4207                 public ArrayList Network_devices {
4208                         get {
4209                                 return network_devices;
4210                         }
4211                 }
4212                 
4213                 public ArrayList Removable_devices {
4214                         get {
4215                                 return removable_devices;
4216                         }
4217                 }
4218                 
4219                 public bool ProcMountAvailable {
4220                         get {
4221                                 return proc_mount_available;
4222                         }
4223                 }
4224                 
4225                 public void GetMounts ()
4226                 {
4227                         if (!proc_mount_available)
4228                                 return;
4229                         
4230                         block_devices.Clear ();
4231                         network_devices.Clear ();
4232                         removable_devices.Clear ();
4233                         
4234                         try {
4235                                 StreamReader sr = new StreamReader ("/proc/mounts");
4236                                 
4237                                 string line = sr.ReadLine ();
4238                                 
4239                                 ArrayList lines = new ArrayList ();
4240                                 while (line != null) {
4241                                         if (lines.IndexOf (line) == -1) { // Avoid duplicates
4242                                                 ProcessProcMountLine (line);
4243                                                 lines.Add (line);
4244                                         }
4245                                         line = sr.ReadLine ();
4246                                 }
4247                                 
4248                                 sr.Close ();
4249                                 
4250                                 block_devices.Sort (mountComparer);
4251                                 network_devices.Sort (mountComparer);
4252                                 removable_devices.Sort (mountComparer);
4253                         } catch {
4254                                 // bla
4255                         }
4256                 }
4257                 
4258                 private void ProcessProcMountLine (string line)
4259                 {
4260                         string[] split = line.Split (new char [] {' '});
4261                         
4262                         if (split != null && split.Length > 0) {
4263                                 Mount mount = new Mount ();
4264                                 
4265                                 if (split [0].StartsWith ("/dev/"))
4266                                         mount.device_short = split [0].Replace ("/dev/", String.Empty);
4267                                 else 
4268                                         mount.device_short = split [0];
4269                                 
4270                                 mount.device_or_filesystem = split [0];
4271                                 mount.mount_point = split [1];
4272                                 
4273                                 // TODO: other removable devices, floppy
4274                                 // ssh
4275                                 
4276                                 // network mount
4277                                 if (split [2] == "nfs") {
4278                                         mount.fsType = FsTypes.nfs;
4279                                         network_devices.Add (mount);
4280                                 } else if (split [2] == "smbfs") {
4281                                         mount.fsType = FsTypes.smbfs;
4282                                         network_devices.Add (mount);
4283                                 } else if (split [2] == "cifs") {
4284                                         mount.fsType = FsTypes.cifs;
4285                                         network_devices.Add (mount);
4286                                 } else if (split [2] == "ncpfs") {
4287                                         mount.fsType = FsTypes.ncpfs;
4288                                         network_devices.Add (mount);
4289                                         
4290                                 } else if (split [2] == "iso9660") { //cdrom
4291                                         mount.fsType = FsTypes.iso9660;
4292                                         removable_devices.Add (mount);
4293                                 } else if (split [2] == "usbfs") { //usb ? not tested
4294                                         mount.fsType = FsTypes.usbfs;
4295                                         removable_devices.Add (mount);
4296                                         
4297                                 } else if (split [0].StartsWith ("/")) { //block devices
4298                                         if (split [1].StartsWith ("/dev/"))  // root static, do not add
4299                                                 return;
4300                                         
4301                                         if (split [2] == "ext2")
4302                                                 mount.fsType = FsTypes.ext2;
4303                                         else if (split [2] == "ext3")
4304                                                 mount.fsType = FsTypes.ext3;
4305                                         else if (split [2] == "reiserfs")
4306                                                 mount.fsType = FsTypes.reiserfs;
4307                                         else if (split [2] == "xfs")
4308                                                 mount.fsType = FsTypes.xfs;
4309                                         else if (split [2] == "vfat")
4310                                                 mount.fsType = FsTypes.vfat;
4311                                         else if (split [2] == "ntfs")
4312                                                 mount.fsType = FsTypes.ntfs;
4313                                         else if (split [2] == "msdos")
4314                                                 mount.fsType = FsTypes.msdos;
4315                                         else if (split [2] == "umsdos")
4316                                                 mount.fsType = FsTypes.umsdos;
4317                                         else if (split [2] == "hpfs")
4318                                                 mount.fsType = FsTypes.hpfs;
4319                                         else if (split [2] == "minix")
4320                                                 mount.fsType = FsTypes.minix;
4321                                         else if (split [2] == "jfs")
4322                                                 mount.fsType = FsTypes.jfs;
4323                                         
4324                                         block_devices.Add (mount);
4325                                 }
4326                         }
4327                 }
4328                 
4329                 public class MountComparer : IComparer
4330                 {
4331                         public int Compare (object mount1, object mount2)
4332                         {
4333                                 return String.Compare (((Mount)mount1).device_short, ((Mount)mount2).device_short);
4334                         }
4335                 }
4336         }
4337         #endregion
4338                 
4339         #region MWFConfig
4340         // easy to use class to store and read internal MWF config settings.
4341         // the config values are stored in the users home dir as a hidden xml file called "mwf_config".
4342         // currently supports int, string, byte, color and arrays (including byte arrays)
4343         // don't forget, when you read a value you still have to cast this value.
4344         //
4345         // usage:
4346         // MWFConfig.SetValue ("SomeClass", "What", value);
4347         // object o = MWFConfig.GetValue ("SomeClass", "What");
4348         //
4349         // example:
4350         // 
4351         // string[] configFileNames = (string[])MWFConfig.GetValue ("FileDialog", "FileNames");
4352         // MWFConfig.SetValue ("FileDialog", "LastFolder", "/home/user");
4353         
4354         internal class MWFConfig
4355         {
4356                 private static MWFConfigInstance Instance = new MWFConfigInstance ();
4357                 
4358                 private static object lock_object = new object();
4359                 
4360                 public static object GetValue (string class_name, string value_name)
4361                 {
4362                         lock (lock_object) {
4363                                 return Instance.GetValue (class_name, value_name);
4364                         }
4365                 }
4366                 
4367                 public static void SetValue (string class_name, string value_name, object value)
4368                 {
4369                         lock (lock_object) {
4370                                 Instance.SetValue (class_name, value_name, value);
4371                         }
4372                 }
4373                 
4374                 public static void Flush ()
4375                 {
4376                         lock (lock_object) {
4377                                 Instance.Flush ();
4378                         }
4379                 }
4380                 
4381                 public static void RemoveClass (string class_name)
4382                 {
4383                         lock (lock_object) {
4384                                 Instance.RemoveClass (class_name);
4385                         }
4386                 }
4387                 
4388                 public static void RemoveClassValue (string class_name, string value_name)
4389                 {
4390                         lock (lock_object) {
4391                                 Instance.RemoveClassValue (class_name, value_name);
4392                         }
4393                 }
4394                 
4395                 public static void RemoveAllClassValues (string class_name)
4396                 {
4397                         lock (lock_object) {
4398                                 Instance.RemoveAllClassValues (class_name);
4399                         }
4400                 }
4401         
4402                 internal class MWFConfigInstance
4403                 {
4404                         Hashtable classes_hashtable = new Hashtable ();
4405                         static string full_file_name;
4406                         static string default_file_name;
4407                         readonly string configName = "MWFConfig";
4408                         static int platform = (int) Environment.OSVersion.Platform;
4409
4410                         static bool IsUnix ()
4411                         {
4412                                 return (platform == 4 || platform == 128);
4413                         }
4414
4415                         static MWFConfigInstance ()
4416                         {
4417                                 string b = "mwf_config";
4418                                 string dir = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
4419                                         
4420                                 if (IsUnix ()){
4421                                         dir = Path.Combine (dir, ".mono");
4422                                         try {
4423                                                 Directory.CreateDirectory (dir);
4424                                         } catch {}
4425                                 } 
4426
4427                                 default_file_name = Path.Combine (dir, b);
4428                                 full_file_name = default_file_name;
4429                         }
4430                         
4431                         public MWFConfigInstance ()
4432                         {
4433                                 Open (default_file_name);
4434                         }
4435                         
4436                         // only for testing
4437                         public MWFConfigInstance (string filename)
4438                         {
4439                                 string path = Path.GetDirectoryName (filename);
4440                                 if (path == null || path == String.Empty) {
4441                                         path = Environment.GetFolderPath (Environment.SpecialFolder.Personal);
4442                                         
4443                                         full_file_name = Path.Combine (path, filename);
4444                                 }  else 
4445                                         full_file_name = filename;
4446
4447                                 Open (full_file_name);
4448                         }                               
4449                         
4450                         ~MWFConfigInstance ()
4451                         {
4452                                 Flush ();
4453                         }
4454                         
4455                         public object GetValue (string class_name, string value_name)
4456                         {
4457                                 ClassEntry class_entry = classes_hashtable [class_name] as ClassEntry;
4458                                 
4459                                 if (class_entry != null)
4460                                         return class_entry.GetValue (value_name);
4461                                 
4462                                 return null;
4463                         }
4464                         
4465                         public void SetValue (string class_name, string value_name, object value)
4466                         {
4467                                 ClassEntry class_entry = classes_hashtable [class_name] as ClassEntry;
4468                                 
4469                                 if (class_entry == null) {
4470                                         class_entry = new ClassEntry ();
4471                                         class_entry.ClassName = class_name;
4472                                         classes_hashtable [class_name] = class_entry;
4473                                 }
4474                                 
4475                                 class_entry.SetValue (value_name, value);
4476                         }
4477                         
4478                         private void Open (string filename)
4479                         {
4480                                 try {
4481                                         XmlTextReader xtr = new XmlTextReader (filename);
4482                                         
4483                                         ReadConfig (xtr);
4484                                         
4485                                         xtr.Close ();
4486                                 } catch (Exception) {
4487                                 }
4488                         }
4489                         
4490                         public void Flush ()
4491                         {
4492                                 try {
4493                                         XmlTextWriter xtw = new XmlTextWriter (full_file_name, null);
4494                                         xtw.Formatting = Formatting.Indented;
4495                                         
4496                                         WriteConfig (xtw);
4497                                         
4498                                         xtw.Close ();
4499
4500                                         if (!IsUnix ())
4501                                                 File.SetAttributes (full_file_name, FileAttributes.Hidden);
4502                                 } catch (Exception){
4503                                 }
4504                         }
4505                         
4506                         public void RemoveClass (string class_name)
4507                         {
4508                                 ClassEntry class_entry = classes_hashtable [class_name] as ClassEntry;
4509                                 
4510                                 if (class_entry != null) {
4511                                         class_entry.RemoveAllClassValues ();
4512                                         
4513                                         classes_hashtable.Remove (class_name);
4514                                 }
4515                         }
4516                         
4517                         public void RemoveClassValue (string class_name, string value_name)
4518                         {
4519                                 ClassEntry class_entry = classes_hashtable [class_name] as ClassEntry;
4520                                 
4521                                 if (class_entry != null) {
4522                                         class_entry.RemoveClassValue (value_name);
4523                                 }
4524                         }
4525                         
4526                         public void RemoveAllClassValues (string class_name)
4527                         {
4528                                 ClassEntry class_entry = classes_hashtable [class_name] as ClassEntry;
4529                                 
4530                                 if (class_entry != null) {
4531                                         class_entry.RemoveAllClassValues ();
4532                                 }
4533                         }
4534                         
4535                         private void ReadConfig (XmlTextReader xtr)
4536                         {
4537                                 if (!CheckForMWFConfig (xtr))
4538                                         return;
4539                                 
4540                                 while (xtr.Read ()) {
4541                                         switch (xtr.NodeType) {
4542                                                 case XmlNodeType.Element:
4543                                                         ClassEntry class_entry = classes_hashtable [xtr.Name] as ClassEntry;
4544                                                         
4545                                                         if (class_entry == null) {
4546                                                                 class_entry = new ClassEntry ();
4547                                                                 class_entry.ClassName = xtr.Name;
4548                                                                 classes_hashtable [xtr.Name] = class_entry;
4549                                                         }
4550                                                         
4551                                                         class_entry.ReadXml (xtr);
4552                                                         break;
4553                                         }
4554                                 }
4555                         }
4556                         
4557                         private bool CheckForMWFConfig (XmlTextReader xtr)
4558                         {
4559                                 if (xtr.Read ()) {
4560                                         if (xtr.NodeType == XmlNodeType.Element) {
4561                                                 if (xtr.Name == configName)
4562                                                         return true;
4563                                         }
4564                                 }
4565                                 
4566                                 return false;
4567                         }
4568                         
4569                         private void WriteConfig (XmlTextWriter xtw)
4570                         {
4571                                 if (classes_hashtable.Count == 0)
4572                                         return;
4573                                 
4574                                 xtw.WriteStartElement (configName);
4575                                 foreach (DictionaryEntry entry in classes_hashtable) {
4576                                         ClassEntry class_entry = entry.Value as ClassEntry;
4577                                         
4578                                         class_entry.WriteXml (xtw);
4579                                 }
4580                                 xtw.WriteEndElement ();
4581                         }
4582                         
4583                         internal class ClassEntry
4584                         {
4585                                 private Hashtable classvalues_hashtable = new Hashtable ();
4586                                 private string className;
4587                                 
4588                                 public string ClassName {
4589                                         set {
4590                                                 className = value;
4591                                         }
4592                                         
4593                                         get {
4594                                                 return className;
4595                                         }
4596                                 }
4597                                 
4598                                 public void SetValue (string value_name, object value)
4599                                 {
4600                                         ClassValue class_value = classvalues_hashtable [value_name] as ClassValue;
4601                                         
4602                                         if (class_value == null) {
4603                                                 class_value = new ClassValue ();
4604                                                 class_value.Name = value_name;
4605                                                 classvalues_hashtable [value_name] = class_value;
4606                                         }
4607                                         
4608                                         class_value.SetValue (value);
4609                                 }
4610                                 
4611                                 public object GetValue (string value_name)
4612                                 {
4613                                         ClassValue class_value = classvalues_hashtable [value_name] as ClassValue;
4614                                         
4615                                         if (class_value == null) {
4616                                                 return null;
4617                                         }
4618                                         
4619                                         return class_value.GetValue ();
4620                                 }
4621                                 
4622                                 public void RemoveAllClassValues ()
4623                                 {
4624                                         classvalues_hashtable.Clear ();
4625                                 }
4626                                 
4627                                 public void RemoveClassValue (string value_name)
4628                                 {
4629                                         ClassValue class_value = classvalues_hashtable [value_name] as ClassValue;
4630                                         
4631                                         if (class_value != null) {
4632                                                 classvalues_hashtable.Remove (value_name);
4633                                         }
4634                                 }
4635                                 
4636                                 public void ReadXml (XmlTextReader xtr)
4637                                 {
4638                                         while (xtr.Read ()) {
4639                                                 switch (xtr.NodeType) {
4640                                                         case XmlNodeType.Element:
4641                                                                 string name = xtr.GetAttribute ("name");
4642                                                                 
4643                                                                 ClassValue class_value = classvalues_hashtable [name] as ClassValue;
4644                                                                 
4645                                                                 if (class_value == null) {
4646                                                                         class_value = new ClassValue ();
4647                                                                         class_value.Name = name;
4648                                                                         classvalues_hashtable [name] = class_value;
4649                                                                 }
4650                                                                 
4651                                                                 class_value.ReadXml (xtr);
4652                                                                 break;
4653                                                                 
4654                                                         case XmlNodeType.EndElement:
4655                                                                 return;
4656                                                 }
4657                                         }
4658                                 }
4659                                 
4660                                 public void WriteXml (XmlTextWriter xtw)
4661                                 {
4662                                         if (classvalues_hashtable.Count == 0)
4663                                                 return;
4664                                         
4665                                         xtw.WriteStartElement (className);
4666                                         
4667                                         foreach (DictionaryEntry entry in classvalues_hashtable) {
4668                                                 ClassValue class_value = entry.Value as ClassValue;
4669                                                 
4670                                                 class_value.WriteXml (xtw);
4671                                         }
4672                                         
4673                                         xtw.WriteEndElement ();
4674                                 }
4675                         }
4676                         
4677                         internal class ClassValue
4678                         {
4679                                 private object value;
4680                                 private string name;
4681                                 
4682                                 public string Name {
4683                                         set {
4684                                                 name = value;
4685                                         }
4686                                         
4687                                         get {
4688                                                 return name;
4689                                         }
4690                                 }
4691                                 
4692                                 public void SetValue (object value)
4693                                 {
4694                                         this.value = value;
4695                                 }
4696                                 public object GetValue ()
4697                                 {
4698                                         return value;
4699                                 }
4700                                 
4701                                 public void ReadXml (XmlTextReader xtr)
4702                                 {
4703                                         string type;
4704                                         string single_value;
4705                                         
4706                                         type = xtr.GetAttribute ("type");
4707                                         
4708                                         if (type == "byte_array" || type.IndexOf ("-array") == -1) {
4709                                                 single_value = xtr.ReadString ();
4710                                                 
4711                                                 if (type == "string") {
4712                                                         value = single_value;
4713                                                 } else
4714                                                 if (type == "int") {
4715                                                         value = Int32.Parse (single_value);
4716                                                 } else
4717                                                 if (type == "byte") {
4718                                                         value = Byte.Parse (single_value);
4719                                                 } else
4720                                                 if (type == "color") {
4721                                                         int color = Int32.Parse (single_value);
4722                                                         value = Color.FromArgb (color);
4723                                                 } else
4724                                                 if (type == "byte-array") {
4725                                                         byte[] b_array = Convert.FromBase64String (single_value);
4726                                                         value = b_array;
4727                                                 }
4728                                         } else {
4729                                                 ReadXmlArrayValues (xtr, type);
4730                                         }
4731                                 }
4732                                 
4733                                 private void ReadXmlArrayValues (XmlTextReader xtr, string type)
4734                                 {
4735                                         ArrayList al = new ArrayList ();
4736                                         
4737                                         while (xtr.Read ()) {
4738                                                 switch (xtr.NodeType) {
4739                                                         case XmlNodeType.Element:
4740                                                                 string single_value = xtr.ReadString ();
4741                                                                 
4742                                                                 if (type == "int-array") {
4743                                                                         int int_val = Int32.Parse (single_value);
4744                                                                         al.Add (int_val);
4745                                                                 } else
4746                                                                 if (type == "string-array") {
4747                                                                         string str_val = single_value;
4748                                                                         al.Add (str_val);
4749                                                                 }
4750                                                                 break;
4751                                                                 
4752                                                         case XmlNodeType.EndElement:
4753                                                                 if (xtr.Name == "value") {
4754                                                                         if (type == "int-array") {
4755                                                                                 value = al.ToArray (typeof(int));
4756                                                                         } else
4757                                                                         if (type == "string-array") {
4758                                                                                 value = al.ToArray (typeof(string));
4759                                                                         } 
4760                                                                         return;
4761                                                                 }
4762                                                                 break;
4763                                                 }
4764                                         }
4765                                 }
4766                                 
4767                                 public void WriteXml (XmlTextWriter xtw)
4768                                 {
4769                                         xtw.WriteStartElement ("value");
4770                                         xtw.WriteAttributeString ("name", name);
4771                                         if (value is Array) {
4772                                                 WriteArrayContent (xtw);
4773                                         } else {
4774                                                 WriteSingleContent (xtw);
4775                                         }
4776                                         xtw.WriteEndElement ();
4777                                 }
4778                                 
4779                                 private void WriteSingleContent (XmlTextWriter xtw)
4780                                 {
4781                                         string type_string = String.Empty;
4782                                         
4783                                         if (value is string)
4784                                                 type_string = "string";
4785                                         else
4786                                         if (value is int)
4787                                                 type_string = "int";
4788                                         else
4789                                         if (value is byte)
4790                                                 type_string = "byte";
4791                                         else
4792                                         if (value is Color)
4793                                                 type_string = "color";
4794                                         
4795                                         xtw.WriteAttributeString ("type", type_string);
4796                                         
4797                                         if (value is Color)
4798                                                 xtw.WriteString (((Color)value).ToArgb ().ToString ());
4799                                         else
4800                                                 xtw.WriteString (value.ToString ());
4801                                 }
4802                                 
4803                                 private void WriteArrayContent (XmlTextWriter xtw)
4804                                 {
4805                                         string type_string = String.Empty;
4806                                         string type_name = String.Empty;
4807                                         
4808                                         if (value is string[]) {
4809                                                 type_string = "string-array";
4810                                                 type_name = "string";
4811                                         } else
4812                                         if (value is int[]) {
4813                                                 type_string = "int-array";
4814                                                 type_name = "int";
4815                                         } else
4816                                         if (value is byte[]) {
4817                                                 type_string = "byte-array";
4818                                                 type_name = "byte";
4819                                         }
4820                                         
4821                                         xtw.WriteAttributeString ("type", type_string);
4822                                         
4823                                         if (type_string != "byte-array") {
4824                                                 Array array = value as Array;
4825                                                 
4826                                                 foreach (object o in array) {
4827                                                         xtw.WriteStartElement (type_name);
4828                                                         xtw.WriteString (o.ToString ());
4829                                                         xtw.WriteEndElement ();
4830                                                 }
4831                                         } else {
4832                                                 byte[] b_array = value as byte [];
4833                                                 
4834                                                 xtw.WriteString (Convert.ToBase64String (b_array, 0, b_array.Length));
4835                                         }
4836                                 }
4837                         }
4838                 }
4839         }
4840         #endregion
4841 }