Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions RetailCoder.VBE/Root/RubberduckModule.cs
Original file line number Diff line number Diff line change
Expand Up @@ -82,6 +82,7 @@ public override void Load()
ApplyDefaultInterfacesConvention(assemblies);
ApplyConfigurationConvention(assemblies);
ApplyAbstractFactoryConvention(assemblies);
Rebind<IFolderBrowserFactory>().To<DialogFactory>().InSingletonScope();

BindCommandsToMenuItems();

Expand Down
1 change: 1 addition & 0 deletions RetailCoder.VBE/Rubberduck.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -467,6 +467,7 @@
<Compile Include="UI\CodeExplorer\Commands\AddClassModuleCommand.cs" />
<Compile Include="UI\CodeExplorer\Commands\AddStdModuleCommand.cs" />
<Compile Include="UI\CodeExplorer\Commands\AddTestModuleCommand.cs" />
<Compile Include="UI\ModernFolderBrowser.cs" />
<Compile Include="VersionCheck\IVersionCheck.cs" />
<Compile Include="UI\Command\MenuItems\CommandBars\AppCommandBarBase.cs" />
<Compile Include="UI\Command\MenuItems\CommandBars\ContextSelectionLabelMenuItem.cs" />
Expand Down
14 changes: 11 additions & 3 deletions RetailCoder.VBE/UI/FileBrowserDialogFactory.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,19 +14,27 @@ IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton,

public class DialogFactory : IFolderBrowserFactory
{
private static readonly bool OldSchool = Environment.OSVersion.Version.Major < 6;

public IFolderBrowser CreateFolderBrowser(string description)
{
return new FolderBrowser(description);
return !OldSchool
? new ModernFolderBrowser(description) as IFolderBrowser
: new FolderBrowser(description);
}

public IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton)
{
return new FolderBrowser(description, showNewFolderButton);
return !OldSchool
? new ModernFolderBrowser(description, showNewFolderButton) as IFolderBrowser
: new FolderBrowser(description, showNewFolderButton);
}

public IFolderBrowser CreateFolderBrowser(string description, bool showNewFolderButton, Environment.SpecialFolder rootFolder)
{
return new FolderBrowser(description, showNewFolderButton, rootFolder);
return !OldSchool
? new ModernFolderBrowser(description, showNewFolderButton, rootFolder) as IFolderBrowser
: new FolderBrowser(description, showNewFolderButton, rootFolder);
}
}
}
121 changes: 121 additions & 0 deletions RetailCoder.VBE/UI/ModernFolderBrowser.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
using System;
using System.Linq;
using System.Reflection;
using System.Windows.Forms;
using FileDialog = System.Windows.Forms.FileDialog;

namespace Rubberduck.UI
{
public class ModernFolderBrowser : IFolderBrowser
{
// ReSharper disable InconsistentNaming
private const BindingFlags DefaultBindingFlags = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;

private static readonly AssemblyName FormsAssemblyName =
Assembly.GetExecutingAssembly()
.GetReferencedAssemblies()
.FirstOrDefault(a => a.FullName.StartsWith("System.Windows.Forms"));

private static readonly Assembly FormsAssembly = Assembly.Load(FormsAssemblyName);
private static readonly Type IFileDialog = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("IFileDialog"));
private static readonly MethodInfo OpenFileDialogCreateVistaDialog = typeof(System.Windows.Forms.OpenFileDialog).GetMethod("CreateVistaDialog", DefaultBindingFlags);
private static readonly MethodInfo OpenFileDialogOnBeforeVistaDialog = typeof(System.Windows.Forms.OpenFileDialog).GetMethod("OnBeforeVistaDialog", DefaultBindingFlags);
private static readonly MethodInfo FileDialogGetOptions = typeof(FileDialog).GetMethod("GetOptions", DefaultBindingFlags);
private static readonly MethodInfo IFileDialogSetOptions = IFileDialog.GetMethod("SetOptions", DefaultBindingFlags);
private static readonly MethodInfo IFileDialogShow = IFileDialog.GetMethod("Show", DefaultBindingFlags);
private static readonly Type FOS = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("FOS"));
private static readonly uint FOS_PICKFOLDERS = (uint)FOS.GetField("FOS_PICKFOLDERS").GetValue(null);
private static readonly Type VistaDialogEvents = FormsAssembly.GetTypes().SingleOrDefault(t => t.Name.Equals("VistaDialogEvents"));
private static readonly ConstructorInfo VistaDialogEventsCtor = VistaDialogEvents.GetConstructors().SingleOrDefault();
private static readonly MethodInfo IFileDialogAdvise = IFileDialog.GetMethod("Advise", DefaultBindingFlags);
private static readonly MethodInfo IFileDialogUnadvise = IFileDialog.GetMethod("Unadvise", DefaultBindingFlags);

// ReSharper restore InconsistentNaming

private readonly System.Windows.Forms.OpenFileDialog _dialog;
private readonly object _newDialog;

// ReSharper disable once UnusedParameter.Local
public ModernFolderBrowser(string description, bool showNewFolderButton, Environment.SpecialFolder rootFolder)
{
_root = rootFolder;
_dialog = new System.Windows.Forms.OpenFileDialog
{
Title = description,
InitialDirectory = Environment.GetFolderPath(_root),
// ReSharper disable once LocalizableElement
Filter = "Folders|\n",
AddExtension = false,
CheckFileExists = false,
DereferenceLinks = true,
Multiselect = false
};
_newDialog = OpenFileDialogCreateVistaDialog.Invoke(_dialog, new object[] { });
OpenFileDialogOnBeforeVistaDialog.Invoke(_dialog, new[] { _newDialog });
var options = (uint)FileDialogGetOptions.Invoke(_dialog, new object[] { }) | FOS_PICKFOLDERS;
IFileDialogSetOptions.Invoke(_newDialog, new object[] { options });
}

public ModernFolderBrowser(string description, bool showNewFolderButton)
: this(description, showNewFolderButton, Environment.SpecialFolder.MyDocuments)
{ }

public ModernFolderBrowser(string description) : this(description, true) { }

public string Description
{
get { return _dialog.Title; }
set { _dialog.Title = value; }
}

public bool ShowNewFolderButton
{
get { return true; }
// ReSharper disable once ValueParameterNotUsed
set { }
}

private Environment.SpecialFolder _root;
public Environment.SpecialFolder RootFolder
{
get { return _root; }
set
{
_root = value;
_dialog.InitialDirectory = Environment.GetFolderPath(_root);
}
}

public string SelectedPath
{
get { return _dialog.FileName; }
set { _dialog.FileName = value; }
}

public DialogResult ShowDialog()
{
var sink = VistaDialogEventsCtor.Invoke(new object[] { _dialog });
var cookie = 0u;
var parameters = new[] { sink, cookie };
IFileDialogAdvise.Invoke(_newDialog, parameters);
//This is the cookie returned as a ref parameter in the call above.
cookie = (uint)parameters[1];
int returnValue;
try
{
returnValue = (int)IFileDialogShow.Invoke(_newDialog, new object[] { IntPtr.Zero });
}
finally
{
IFileDialogUnadvise.Invoke(_newDialog, new object[] { cookie });
GC.KeepAlive(sink);
}
return returnValue == 0 ? DialogResult.OK : DialogResult.Cancel;
}

public void Dispose()
{
_dialog.Dispose();
}
}
}