///
/// Copyright © 2003-2008 JetBrains s.r.o.
/// You may distribute under the terms of the GNU General Public License, as published by the Free Software Foundation, version 2 (see License.txt in the repository root folder).
///
using System;
using System.Collections;
using System.Windows.Forms;
using JetBrains.DataStructures;
using JetBrains.Omea.Base;
using JetBrains.Omea.Diagnostics;
using JetBrains.Omea.GUIControls;
using JetBrains.Omea.OpenAPI;
using JetBrains.Omea.RemoteControl;
using Microsoft.Win32;
namespace JetBrains.Omea
{
public class ProtocolHandlerManager : ProtocolHandlersInResourceStore, IProtocolHandlerManager
{
private readonly HashMap _handlers = new HashMap();
private readonly HashMap _makeDefaultHandler = new HashMap();
private string _openurl = null;
private readonly OnRemoteInvokeDelegate _onRemoteInvokeDelegate = null;
private delegate int OnRemoteInvokeDelegate( string url );
private const string METHOD_NAME = "Omea.ProtocolHandlerManager.OpenURL";
public ProtocolHandlerManager()
{
_onRemoteInvokeDelegate = OnRemoteInvoke;
}
public void CheckProtocols( IWin32Window parent )
{
Core.UserInterfaceAP.QueueJob( new CheckProtocolsDelegate( CheckProtocolsImpl ), parent );
}
private delegate void CheckProtocolsDelegate( IWin32Window parent );
public static HashMap GetProtocols( IResourceList protocolHandlers )
{
HashMap protocolSet = new HashMap( protocolHandlers.Count );
foreach ( IResource protocol in protocolHandlers )
{
string friendlyName = protocol.GetPropText( _propFriendlyName );
HashMap.Entry entry = protocolSet.GetEntry( friendlyName );
if ( entry == null )
{
ArrayList list = new ArrayList();
list.Add( protocol );
protocolSet.Add( friendlyName, list );
}
else
{
((ArrayList)entry.Value).Add( protocol );
}
}
return protocolSet;
}
private void CheckProtocolsImpl( IWin32Window parent )
{
IResourceList protocolHandlers = GetProtocolsToCheck();
HashMap protocolSet = GetProtocols( protocolHandlers );
foreach ( HashMap.Entry entry in protocolSet )
{
ArrayList list = (ArrayList)entry.Value;
foreach ( IResource protocol in list )
{
string protocolName = protocol.GetStringProp( PROTOCOL );
if ( !ProtocolHandlersInRegistry.IsDefaultHandler( protocolName ) )
{
CheckProtocols( parent, list );
break;
}
}
}
}
private static void CheckProtocols( IWin32Window parent, ArrayList list )
{
string friendlyName = ((IResource)list[0]).GetPropText( _propFriendlyName );
string message = Core.ProductFullName + " is not your default " + friendlyName +
". Would you like to make it your default " + friendlyName + "?";
string checkBoxText = "&Check if " + Core.ProductFullName + " is the default " + friendlyName + " on startup";
MessageBoxWithCheckBox.Result result =
MessageBoxWithCheckBox.ShowYesNo( parent, message, Core.ProductFullName, checkBoxText, true );
foreach ( IResource protocol in list )
{
string protocolName = protocol.GetStringProp( PROTOCOL );
if ( !result.Checked )
{
SetCheckNeeded( protocolName, false );
}
if ( result.IdPressedButton == (int)DialogResult.Yes )
{
SetAsDefaultHandler( protocol, result.Checked );
}
}
}
private void InvokeMakeDefault( string protocol )
{
Guard.NullArgument( protocol, "protocol" );
lock ( _makeDefaultHandler )
{
HashMap.Entry entry = _makeDefaultHandler.GetEntry( protocol );
if ( entry != null )
{
((MethodInvoker)entry.Value).Invoke();
}
}
}
public static void SetAsDefaultHandler( IResource resProtocol, bool check )
{
ProtocolHandlerManager manager = Core.ProtocolHandlerManager as ProtocolHandlerManager;
Guard.NullLocalVariable( manager, "manager" );
string protocol = resProtocol.GetPropText( _propProtocol );
ProtocolHandlersInRegistry.SetAsDefaultHandler( protocol, resProtocol.GetPropText( _propFriendlyName ) );
SetCheckNeeded( protocol, check );
manager.InvokeMakeDefault( protocol );
}
public int Registrations { get { return _handlers.Count; } }
private class ProtocolHandler
{
private readonly string _protocol;
private readonly string _friendlyName;
private readonly ProtocolHandlerCallback _handler;
public ProtocolHandler( string protocol, string friendlyName, ProtocolHandlerCallback handler )
{
_protocol = protocol;
_friendlyName = friendlyName;
_handler = handler;
}
public string Protocol { get { return _protocol; } }
public string FriendlyName { get { return _friendlyName; } }
public ProtocolHandlerCallback ProtocolHandlerCallback { get { return _handler; } }
public void Invoke( string url )
{
_handler.Invoke( url );
}
}
public int OnRemoteInvoke( string url )
{
try
{
Invoke( url );
}
catch ( Exception exception )
{
Tracer._TraceException( exception );
}
return 0;
}
public void SetOpenURL( string openurl )
{
Guard.NullArgument( openurl, "openurl" );
_openurl = openurl;
}
public void AddRemoteCall()
{
Core.RemoteControllerManager.AddRemoteCall( METHOD_NAME, _onRemoteInvokeDelegate );
}
public void RemoteInvoke( int port, string secureKey )
{
if ( _openurl != null )
{
new RemoteControlClient( port, secureKey ).SendRequest( METHOD_NAME, new object[] { "url", _openurl });
}
}
public void InvokeOpenUrl( )
{
Invoke( _openurl );
}
public bool IsOpenUrlRequested { get { return _openurl != null; } }
public void Invoke( string url )
{
if ( url == null ) return;
int pos = url.IndexOf( ':' );
if ( pos != -1 )
{
string protocol = url.Substring( 0, pos );
HashMap.Entry entry = null;
lock ( _handlers )
{
entry = _handlers.GetEntry( protocol );
}
if ( entry != null )
{
++pos;
string URL = url.Substring( pos, url.Length - pos );
ProtocolHandler handler = entry.Value as ProtocolHandler;
if ( handler != null )
{
try
{
handler.Invoke( URL );
}
catch ( Exception exception )
{
Core.ReportException( exception, ExceptionReportFlags.AttachLog );
}
}
}
}
}
private static void CheckParameters( string protocol, string friendlyName, ProtocolHandlerCallback handler )
{
Guard.NullArgument( protocol, "protocol" );
Guard.NullArgument( friendlyName, "friendlyName" );
Guard.NullArgument( handler, "handler" );
if ( protocol.Length == 0 )
{
throw new ArgumentException( "Zero length for protocol name", "protocol" );
}
if ( protocol.IndexOf( ':' ) != -1 )
{
throw new ArgumentException( "Protocol name must not include ':' symbol", "protocol" );
}
}
///
/// Registers new URL protocol handler.
///
/// URL protocol.
/// Friendly name of URL protocol.
/// Delegate that uses as protocol handler for processing requested urls.
public void RegisterProtocolHandler( string protocol, string friendlyName, ProtocolHandlerCallback handler )
{
CheckParameters( protocol, friendlyName, handler );
lock ( _handlers )
{
_handlers[ protocol ] = new ProtocolHandler( protocol, friendlyName, handler );
SaveProtocolSettings( protocol, friendlyName, Default.NoChanges );
}
}
///
/// Registers new URL protocol handler.
///
/// URL protocol.
/// Friendly name of URL protocol.
/// Delegate that uses as protocol handler for processing requested urls.
/// Delegate that is invoked when protocol is set as default.
public void RegisterProtocolHandler( string protocol, string friendlyName, ProtocolHandlerCallback handler, MethodInvoker makeDefaultHandler )
{
RegisterProtocolHandler( protocol, friendlyName, handler );
Guard.NullArgument( makeDefaultHandler, "makeDefaultHandler" );
lock ( _makeDefaultHandler )
{
_makeDefaultHandler[ protocol ] = makeDefaultHandler;
}
}
}
internal class ProtocolHandlersInRegistry
{
private const string URLProtocol = "URL Protocol";
private const string SHELL_COMMAND = "\\shell\\open\\command";
public static bool IsDefaultHandler( string protocol )
{
Guard.NullArgument( protocol, "protocol" );
string protocolKey = "Software\\Classes\\" + protocol;
string urlProtocol = RegUtil.GetValue( Registry.CurrentUser, protocolKey, URLProtocol ) as string;
if ( urlProtocol != null )
{
string command = RegUtil.GetValue( Registry.CurrentUser, protocolKey + SHELL_COMMAND, "" ) as string;
if ( command != null )
{
return command.ToLower().IndexOf( Application.ExecutablePath.ToLower() ) != -1;
}
}
return false;
}
public static void SetAsDefaultHandler( string protocol, string friendlyName )
{
Guard.NullArgument( protocol, "protocol" );
Guard.NullArgument( friendlyName, "friendlyName" );
string protocolKey = "Software\\Classes\\" + protocol;
if ( !RegUtil.CreateSubKey( Registry.CurrentUser, protocolKey ) ) return;
RegUtil.SetValue( Registry.CurrentUser, protocolKey, "", "URL:" + friendlyName );
RegUtil.SetValue( Registry.CurrentUser, protocolKey, URLProtocol, "" );
if ( RegUtil.CreateSubKey( Registry.CurrentUser, protocolKey + SHELL_COMMAND ) )
{
RegUtil.SetValue( Registry.CurrentUser, protocolKey + SHELL_COMMAND, "",
"\"" + Application.ExecutablePath + "\"" + " -openurl %1" );
}
if ( RegUtil.CreateSubKey( Registry.CurrentUser, protocolKey + "\\DefaultIcon" ) )
{
RegUtil.SetValue( Registry.CurrentUser, protocolKey + "\\DefaultIcon", "",
"\"" + Application.ExecutablePath + "\"" );
}
}
}
public class ProtocolHandlersInResourceStore
{
private static bool _registered = false;
public const string PROTOCOL_HANDLER = "ProtocolHandler";
public const string FNAME = "ProtocolFriendlyName";
public const string PROTOCOL = "Protocol";
public const string DEFAULT = "DefaultProtocol";
public const string CHECK = "Check";
public static int _propProtocol;
public static int _propFriendlyName;
public static int _propDefault;
public static int _propCheck;
public ProtocolHandlersInResourceStore()
{
_registered = false;
}
private static void CheckRegistration()
{
if ( !_registered )
{
throw new ApplicationException( "ProtocolHandlersInResourceStore: Resoures were not registered" );
}
}
public IResourceList GetProtocolsToCheck( )
{
return Core.ResourceStore.FindResources( PROTOCOL_HANDLER, _propCheck, true );
}
public IResource GetProtocolResource( string protocol )
{
CheckRegistration();
return Core.ResourceStore.FindUniqueResource( PROTOCOL_HANDLER, _propProtocol, protocol );
}
public static IResourceList GetProtocolHandlersList()
{
CheckRegistration();
return Core.ResourceStore.GetAllResources( PROTOCOL_HANDLER );
}
public IResourceList ProtocolHandlersList
{
get
{
return GetProtocolHandlersList();
}
}
public void RegisterResources()
{
_registered = true;
IResourceStore RS = Core.ResourceStore;
_propProtocol = RS.PropTypes.Register( PROTOCOL, PropDataType.String, PropTypeFlags.Internal );
_propFriendlyName = RS.PropTypes.Register( FNAME, PropDataType.String, PropTypeFlags.Internal );
_propDefault = RS.PropTypes.Register( DEFAULT, PropDataType.Bool, PropTypeFlags.Internal );
_propCheck = RS.PropTypes.Register( CHECK, PropDataType.Bool, PropTypeFlags.Internal );
RS.ResourceTypes.Register( PROTOCOL_HANDLER, PROTOCOL_HANDLER, FNAME + " | " + PROTOCOL, ResourceTypeFlags.Internal | ResourceTypeFlags.NoIndex );
RS.RegisterUniqueRestriction( PROTOCOL_HANDLER, _propProtocol );
}
public enum Default
{
Yes,
No,
NoChanges
}
public static void SetCheckNeeded( string protocol, bool check )
{
IResource resProtocol = Core.ResourceStore.FindUniqueResource( PROTOCOL_HANDLER, _propProtocol, protocol );
if ( resProtocol != null )
{
ResourceProxy proxy = new ResourceProxy( resProtocol );
proxy.BeginUpdate();
proxy.AsyncPriority = JobPriority.Immediate;
proxy.SetProp( _propCheck, check );
proxy.EndUpdate();
}
}
public bool IsCheckNeeded( string protocol )
{
IResource resProtocol = Core.ResourceStore.FindUniqueResource( PROTOCOL_HANDLER, _propProtocol, protocol );
if ( resProtocol != null )
{
return resProtocol.HasProp( _propCheck );
}
return false;
}
public void SaveProtocolSettings( IResource resource, string friendlyName, bool defaultProtocol )
{
CheckRegistration();
ResourceProxy proxy = new ResourceProxy( resource );
proxy.BeginUpdate();
SaveProtocolSettings( proxy, friendlyName, defaultProtocol ? Default.Yes : Default.No );
}
private static void SaveProtocolSettings( ResourceProxy proxy, string friendlyName, Default defProtocol )
{
CheckRegistration();
proxy.AsyncPriority = JobPriority.Immediate;
proxy.SetProp( _propFriendlyName, friendlyName );
if ( defProtocol != Default.NoChanges )
{
proxy.SetProp( _propDefault, defProtocol == Default.Yes );
}
proxy.EndUpdate();
if ( proxy.Resource.HasProp( _propDefault ) )
{
ProtocolHandlersInRegistry.SetAsDefaultHandler( proxy.Resource.GetPropText( _propProtocol ), friendlyName );
}
}
protected static void SaveProtocolSettings( string protocol, string friendlyName, Default defProtocol )
{
CheckRegistration();
IResource resProtocol = Core.ResourceStore.FindUniqueResource( PROTOCOL_HANDLER, _propProtocol, protocol );
ResourceProxy proxy = null;
if ( resProtocol == null )
{
proxy = ResourceProxy.BeginNewResource( PROTOCOL_HANDLER );
proxy.SetProp( _propCheck, true );
}
else
{
proxy = new ResourceProxy( resProtocol );
proxy.BeginUpdate();
}
proxy.SetProp( _propProtocol, protocol );
SaveProtocolSettings( proxy, friendlyName, defProtocol );
}
}
}