You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
290 lines
9.1 KiB
290 lines
9.1 KiB
// <file> |
|
// <copyright see="prj:///doc/copyright.txt"/> |
|
// <license see="prj:///doc/license.txt"/> |
|
// <owner name="Mike Krüger" email="mike@icsharpcode.net"/> |
|
// <version>$Revision$</version> |
|
// </file> |
|
|
|
using System; |
|
using System.Diagnostics; |
|
using System.Windows; |
|
using System.Windows.Forms; |
|
|
|
using ICSharpCode.Core; |
|
using ICSharpCode.Core.WinForms; |
|
|
|
namespace ICSharpCode.SharpDevelop.Gui |
|
{ |
|
public static class WorkbenchSingleton |
|
{ |
|
const string uiIconStyle = "IconMenuItem.IconMenuStyle"; |
|
const string uiLanguageProperty = "CoreProperties.UILanguage"; |
|
const string workbenchMemento = "WorkbenchMemento"; |
|
const string activeContentState = "Workbench.ActiveContent"; |
|
|
|
static IWorkbench workbench; |
|
|
|
/// <summary> |
|
/// Gets the main form. Returns null in unit-testing mode. |
|
/// </summary> |
|
public static IWin32Window MainWin32Window { |
|
get { |
|
if (workbench != null) { |
|
return workbench.MainWin32Window; |
|
} |
|
return null; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Gets the main window. Returns null in unit-testing mode. |
|
/// </summary> |
|
public static Window MainWindow { |
|
get { |
|
if (workbench != null) { |
|
return workbench.MainWindow; |
|
} |
|
return null; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Gets the workbench. Returns null in unit-testing mode. |
|
/// </summary> |
|
public static IWorkbench Workbench { |
|
get { |
|
return workbench; |
|
} |
|
} |
|
|
|
public static IStatusBarService StatusBar { |
|
get { |
|
return workbench != null ? workbench.StatusBar : null; |
|
} |
|
} |
|
|
|
public static void InitializeWorkbench(IWorkbench workbench, IWorkbenchLayout layout) |
|
{ |
|
WorkbenchSingleton.workbench = workbench; |
|
|
|
DisplayBindingService.InitializeService(); |
|
LayoutConfiguration.LoadLayoutConfiguration(); |
|
FileService.InitializeService(); |
|
DomHostCallback.Register(); // must be called after StatusBarService.Initialize() |
|
ParserService.InitializeParserService(); |
|
TaskService.Initialize(); |
|
Bookmarks.BookmarkManager.Initialize(); |
|
Project.CustomToolsService.Initialize(); |
|
Project.BuildModifiedProjectsOnlyService.Initialize(); |
|
|
|
var messageService = (WinFormsMessageService)Core.Services.ServiceManager.Instance.MessageService; |
|
messageService.DialogOwner = workbench.MainWin32Window; |
|
Debug.Assert(messageService.DialogOwner != null); |
|
messageService.DialogSynchronizeInvoke = workbench.SynchronizingObject; |
|
|
|
workbench.Initialize(); |
|
workbench.SetMemento(PropertyService.Get(workbenchMemento, new Properties())); |
|
workbench.WorkbenchLayout = layout; |
|
|
|
ApplicationStateInfoService.RegisterStateGetter(activeContentState, delegate { return WorkbenchSingleton.Workbench.ActiveContent; }); |
|
|
|
OnWorkbenchCreated(); |
|
|
|
// initialize workbench-dependent services: |
|
Project.ProjectService.InitializeService(); |
|
NavigationService.InitializeService(); |
|
|
|
workbench.ActiveContentChanged += delegate { |
|
Debug.WriteLine("ActiveContentChanged to " + workbench.ActiveContent); |
|
LoggingService.Debug("ActiveContentChanged to " + workbench.ActiveContent); |
|
}; |
|
workbench.ActiveViewContentChanged += delegate { |
|
Debug.WriteLine("ActiveViewContentChanged to " + workbench.ActiveViewContent); |
|
LoggingService.Debug("ActiveViewContentChanged to " + workbench.ActiveViewContent); |
|
}; |
|
workbench.ActiveWorkbenchWindowChanged += delegate { |
|
Debug.WriteLine("ActiveWorkbenchWindowChanged to " + workbench.ActiveWorkbenchWindow); |
|
LoggingService.Debug("ActiveWorkbenchWindowChanged to " + workbench.ActiveWorkbenchWindow); |
|
}; |
|
} |
|
|
|
/// <summary> |
|
/// Runs workbench cleanup. |
|
/// Is called by ICSharpCode.SharpDevelop.Sda and should not be called manually! |
|
/// </summary> |
|
public static void OnWorkbenchUnloaded() |
|
{ |
|
Project.ProjectService.CloseSolution(); |
|
NavigationService.Unload(); |
|
|
|
ApplicationStateInfoService.UnregisterStateGetter(activeContentState); |
|
|
|
WorkbenchUnloaded(null, EventArgs.Empty); |
|
|
|
FileService.Unload(); |
|
} |
|
|
|
#region Safe Thread Caller |
|
public static bool InvokeRequired { |
|
get { |
|
if (workbench == null) |
|
return false; // unit test mode, don't crash |
|
else |
|
return workbench.SynchronizingObject.InvokeRequired; |
|
} |
|
} |
|
|
|
/// <summary> |
|
/// Throws an exception if the current thread is not the main thread. |
|
/// For performance reasons, the thread check is only done in debug builds. |
|
/// </summary> |
|
[Conditional("DEBUG")] |
|
internal static void DebugAssertMainThread() |
|
{ |
|
AssertMainThread(); |
|
} |
|
|
|
/// <summary> |
|
/// Throws an exception if the current thread is not the main thread. |
|
/// </summary> |
|
public static void AssertMainThread() |
|
{ |
|
if (InvokeRequired) { |
|
throw new InvalidOperationException("This operation can be called on the main thread only."); |
|
} |
|
} |
|
|
|
readonly static object[] emptyObjectArray = new object[0]; |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe. WARNING: This method waits for the result of the |
|
/// operation, which can result in a dead-lock when the main thread waits for a lock |
|
/// held by this thread! |
|
/// </summary> |
|
public static R SafeThreadFunction<R>(Func<R> method) |
|
{ |
|
return (R)workbench.SynchronizingObject.Invoke(method, emptyObjectArray); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe. WARNING: This method waits for the result of the |
|
/// operation, which can result in a dead-lock when the main thread waits for a lock |
|
/// held by this thread! |
|
/// </summary> |
|
public static R SafeThreadFunction<A, R>(Func<A, R> method, A arg1) |
|
{ |
|
return (R)workbench.SynchronizingObject.Invoke(method, new object[] { arg1 }); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe. WARNING: This method waits for the result of the |
|
/// operation, which can result in a dead-lock when the main thread waits for a lock |
|
/// held by this thread! |
|
/// </summary> |
|
public static void SafeThreadCall(Action method) |
|
{ |
|
workbench.SynchronizingObject.Invoke(method, emptyObjectArray); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe. WARNING: This method waits for the result of the |
|
/// operation, which can result in a dead-lock when the main thread waits for a lock |
|
/// held by this thread! |
|
/// </summary> |
|
public static void SafeThreadCall<A>(Action<A> method, A arg1) |
|
{ |
|
workbench.SynchronizingObject.Invoke(method, new object[] { arg1 }); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe. WARNING: This method waits for the result of the |
|
/// operation, which can result in a dead-lock when the main thread waits for a lock |
|
/// held by this thread! |
|
/// </summary> |
|
public static void SafeThreadCall<A, B>(Action<A, B> method, A arg1, B arg2) |
|
{ |
|
workbench.SynchronizingObject.Invoke(method, new object[] { arg1, arg2 }); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe. WARNING: This method waits for the result of the |
|
/// operation, which can result in a dead-lock when the main thread waits for a lock |
|
/// held by this thread! |
|
/// </summary> |
|
public static void SafeThreadCall<A, B, C>(Action<A, B, C> method, A arg1, B arg2, C arg3) |
|
{ |
|
workbench.SynchronizingObject.Invoke(method, new object[] { arg1, arg2, arg3 }); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe without waiting for the returned value. |
|
/// </summary> |
|
public static void SafeThreadAsyncCall(Action method) |
|
{ |
|
workbench.SynchronizingObject.BeginInvoke(method, emptyObjectArray); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe without waiting for the returned value. |
|
/// </summary> |
|
public static void SafeThreadAsyncCall<A>(Action<A> method, A arg1) |
|
{ |
|
workbench.SynchronizingObject.BeginInvoke(method, new object[] { arg1 }); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe without waiting for the returned value. |
|
/// </summary> |
|
public static void SafeThreadAsyncCall<A, B>(Action<A, B> method, A arg1, B arg2) |
|
{ |
|
workbench.SynchronizingObject.BeginInvoke(method, new object[] { arg1, arg2 }); |
|
} |
|
|
|
/// <summary> |
|
/// Makes a call GUI threadsafe without waiting for the returned value. |
|
/// </summary> |
|
public static void SafeThreadAsyncCall<A, B, C>(Action<A, B, C> method, A arg1, B arg2, C arg3) |
|
{ |
|
workbench.SynchronizingObject.BeginInvoke(method, new object[] { arg1, arg2, arg3 }); |
|
} |
|
|
|
/// <summary> |
|
/// Calls a method on the GUI thread, but delays the call a bit. |
|
/// </summary> |
|
public static void CallLater(TimeSpan delay, Action method) |
|
{ |
|
int delayMilliseconds = (int)delay.TotalMilliseconds; |
|
if (delayMilliseconds < 0) |
|
throw new ArgumentOutOfRangeException("delay", delay, "Value must be positive"); |
|
if (method == null) |
|
throw new ArgumentNullException("method"); |
|
SafeThreadAsyncCall( |
|
delegate { |
|
Timer t = new Timer(); |
|
t.Interval = Math.Max(1, delayMilliseconds); |
|
t.Tick += delegate { |
|
t.Stop(); |
|
t.Dispose(); |
|
method(); |
|
}; |
|
t.Start(); |
|
}); |
|
} |
|
#endregion |
|
|
|
static void OnWorkbenchCreated() |
|
{ |
|
WorkbenchCreated(null, EventArgs.Empty); |
|
} |
|
|
|
/// <summary> |
|
/// Is called, when the workbench is created |
|
/// </summary> |
|
public static event EventHandler WorkbenchCreated = delegate {}; |
|
|
|
/// <summary> |
|
/// Is called, when the workbench is unloaded |
|
/// </summary> |
|
public static event EventHandler WorkbenchUnloaded = delegate {}; |
|
} |
|
}
|
|
|