3
using System.Collections.Generic;
5
using System.Threading;
6
using MonoDevelop.Components.Extensions;
7
using System.Windows.Forms;
8
using MonoDevelop.Core;
11
namespace MonoDevelop.Platform
13
class SelectFileDialogHandler : ISelectFileDialogHandler
15
volatile Form rootForm;
17
public bool Run (SelectFileDialogData data)
19
var parentWindow = data.TransientFor ?? MessageService.RootWindow;
20
parentWindow.FocusInEvent += OnParentFocusIn;
22
bool result = RunWinUIMethod (RunDialog, data);
24
parentWindow.FocusInEvent -= OnParentFocusIn;
25
parentWindow.Present ();
30
void OnParentFocusIn (object o, EventArgs args)
33
rootForm.BeginInvoke (new Action (rootForm.Activate));
36
bool RunDialog (SelectFileDialogData data)
38
Application.EnableVisualStyles ();
40
CommonDialog dlg = null;
41
if (data.Action == Gtk.FileChooserAction.Open)
42
dlg = new OpenFileDialog();
43
else if (data.Action == Gtk.FileChooserAction.Save)
44
dlg = new SaveFileDialog();
45
else if (data.Action == Gtk.FileChooserAction.SelectFolder)
46
dlg = new FolderBrowserDialog ();
48
if (dlg is FileDialog)
49
SetCommonFormProperties (data, (FileDialog)dlg);
51
SetFolderBrowserProperties (data, (FolderBrowserDialog)dlg);
54
rootForm = new WinFormsRoot ();
55
if (dlg.ShowDialog (rootForm) == DialogResult.Cancel) {
59
if (dlg is FileDialog) {
60
var fileDlg = dlg as FileDialog;
61
FilePath[] paths = new FilePath [fileDlg.FileNames.Length];
62
for (int n=0; n < fileDlg.FileNames.Length; n++)
63
paths [n] = fileDlg.FileNames [n];
64
data.SelectedFiles = paths;
66
var folderDlg = dlg as FolderBrowserDialog;
67
data.SelectedFiles = new [] { new FilePath (folderDlg.SelectedPath) };
74
// Any native Winforms component needs to run on a thread marked as single-threaded apartment (STAThread).
75
// Marking the MD's Main method with STAThread has historically shown to be a source of several problems,
76
// thus we isolate the calls by creating a new thread for our calls.
77
// More info here: http://blogs.msdn.com/b/jfoscoding/archive/2005/04/07/406341.aspx
78
internal static bool RunWinUIMethod<T> (Func<T,bool> func, T data) where T : SelectFileDialogData
81
var t = new Thread (() => {
84
} catch (Exception ex) {
85
LoggingService.LogError ("Unhandled exception handling a native dialog", ex);
88
t.Name = "Win32 Interop Thread";
89
t.IsBackground = true;
90
t.SetApartmentState (ApartmentState.STA);
94
DispatchService.RunPendingEvents ();
99
internal static void SetCommonFormProperties (SelectFileDialogData data, FileDialog dialog)
101
if (!string.IsNullOrEmpty (data.Title))
102
dialog.Title = data.Title;
104
dialog.AddExtension = true;
105
dialog.Filter = GetFilterFromData (data.Filters);
106
dialog.FilterIndex = data.DefaultFilter == null ? 1 : GetDefaultFilterIndex (data);
108
dialog.InitialDirectory = data.CurrentFolder;
110
// FileDialog.FileName expects anything but a directory name.
111
if (!Directory.Exists (data.InitialFileName))
112
dialog.FileName = data.InitialFileName;
114
OpenFileDialog openDialog = dialog as OpenFileDialog;
115
if (openDialog != null)
116
openDialog.Multiselect = data.SelectMultiple;
119
static int GetDefaultFilterIndex (SelectFileDialogData data)
121
var defFilter = data.DefaultFilter;
122
int idx = data.Filters.IndexOf (defFilter) + 1;
124
// FileDialog doesn't show the file extension when saving a file,
125
// so we try to look fo the precise filter if none was specified.
126
if (data.Action == Gtk.FileChooserAction.Save && defFilter.Patterns.Contains ("*")) {
127
string ext = Path.GetExtension (data.InitialFileName);
129
if (!String.IsNullOrEmpty (ext))
130
for (int i = 0; i < data.Filters.Count; i++) {
131
var filter = data.Filters [i];
132
foreach (string pattern in filter.Patterns)
133
if (pattern.EndsWith (ext))
141
static void SetFolderBrowserProperties (SelectFileDialogData data, FolderBrowserDialog dialog)
143
if (!string.IsNullOrEmpty (data.Title))
144
dialog.Description = data.Title;
146
dialog.SelectedPath = data.CurrentFolder;
149
static string GetFilterFromData (IList<SelectFileDialogFilter> filters)
151
if (filters == null || filters.Count == 0)
154
var sb = new StringBuilder ();
155
foreach (var f in filters) {
161
for (int i = 0; i < f.Patterns.Count; i++) {
165
sb.Append (f.Patterns [i]);
169
return sb.ToString ();