Browse Source

fix #524: Reentrancy in 'external change' dialogs

pull/505/merge
Siegfried Pammer 11 years ago
parent
commit
d303714f8d
  1. 49
      src/Main/Base/Project/Src/Project/ProjectChangeWatcher.cs
  2. 65
      src/Main/Base/Project/Workbench/FileChangeWatcher.cs

49
src/Main/Base/Project/Src/Project/ProjectChangeWatcher.cs

@ -172,27 +172,36 @@ namespace ICSharpCode.SharpDevelop.Project @@ -172,27 +172,36 @@ namespace ICSharpCode.SharpDevelop.Project
static void MainFormActivated()
{
if (wasChangedExternally && !showingMessageBox) {
if (ProjectService.OpenSolution != null) {
// Set wasChangedExternally=false only after the dialog is closed,
// so that additional changes to the project while the dialog is open
// don't cause it to appear twice.
// The MainFormActivated event occurs when the dialog is closed before
// we get a change to set wasChangedExternally=false, so we use 'showingMessageBox'
// to prevent the dialog from appearing infititely.
showingMessageBox = true;
int result = MessageService.ShowCustomDialog(MessageService.DefaultMessageBoxTitle, "${res:ICSharpCode.SharpDevelop.Project.SolutionAlteredExternallyMessage}", 0, 1, "${res:ICSharpCode.SharpDevelop.Project.ReloadSolution}", "${res:ICSharpCode.SharpDevelop.Project.KeepOldSolution}", "${res:ICSharpCode.SharpDevelop.Project.CloseSolution}");
showingMessageBox = false;
wasChangedExternally = false;
if (result == 0)
SD.ProjectService.OpenSolutionOrProject(ProjectService.OpenSolution.FileName);
else if (result == 2)
new CloseSolution().Run();
} else {
wasChangedExternally = false;
if (wasChangedExternally) {
if (!showingMessageBox) {
if (ProjectService.OpenSolution != null) {
// Set wasChangedExternally=false only after the dialog is closed,
// so that additional changes to the project while the dialog is open
// don't cause it to appear twice.
// The MainFormActivated event occurs when the dialog is closed before
// we get a change to set wasChangedExternally=false, so we use 'showingMessageBox'
// to prevent the dialog from appearing infititely.
showingMessageBox = true;
int result = MessageService.ShowCustomDialog(MessageService.DefaultMessageBoxTitle, "${res:ICSharpCode.SharpDevelop.Project.SolutionAlteredExternallyMessage}", 0, 1, "${res:ICSharpCode.SharpDevelop.Project.ReloadSolution}", "${res:ICSharpCode.SharpDevelop.Project.KeepOldSolution}", "${res:ICSharpCode.SharpDevelop.Project.CloseSolution}");
showingMessageBox = false;
wasChangedExternally = false;
if (result == 1) {
FileChangeWatcher.AskForReload();
} else {
FileChangeWatcher.CancelReloadQueue();
if (result == 0) {
SD.ProjectService.OpenSolutionOrProject(ProjectService.OpenSolution.FileName);
} else {
new CloseSolution().Run();
}
}
} else {
wasChangedExternally = false;
}
}
} else {
FileChangeWatcher.AskForReload();
}
}

65
src/Main/Base/Project/Workbench/FileChangeWatcher.cs

@ -18,10 +18,7 @@ @@ -18,10 +18,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Windows.Forms;
using ICSharpCode.SharpDevelop.Gui;
using ICSharpCode.Core;
namespace ICSharpCode.SharpDevelop.Workbench
@ -206,21 +203,65 @@ namespace ICSharpCode.SharpDevelop.Workbench @@ -206,21 +203,65 @@ namespace ICSharpCode.SharpDevelop.Workbench
string fileName = file.FileName;
if (!File.Exists(fileName))
return;
string message = StringParser.Parse(
"${res:ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.TextEditorDisplayBinding.FileAlteredMessage}",
new StringTagPair("File", Path.GetFullPath(fileName))
);
if ((AutoLoadExternalChangesOption && file.IsDirty == false)
|| MessageService.AskQuestion(message, StringParser.Parse("${res:MainWindow.DialogName}")))
{
if (AutoLoadExternalChangesOption && !file.IsDirty) {
if (File.Exists(fileName)) {
file.ReloadFromDisk();
}
} else {
file.MakeDirty();
QueueFileForReloadDialog(file);
}
}
}
#region Reload Queue
static readonly HashSet<OpenedFile> queue = new HashSet<OpenedFile>();
static volatile bool currentlyReloading;
static void QueueFileForReloadDialog(OpenedFile file)
{
if (file == null)
throw new ArgumentNullException("file");
lock (queue) {
queue.Add(file);
}
}
public static void AskForReload()
{
if (currentlyReloading) return;
currentlyReloading = true;
try {
lock (queue) {
foreach (var file in queue) {
string fileName = file.FileName;
if (!File.Exists(fileName))
continue;
string message = StringParser.Parse(
"${res:ICSharpCode.SharpDevelop.DefaultEditor.Gui.Editor.TextEditorDisplayBinding.FileAlteredMessage}",
new StringTagPair("File", Path.GetFullPath(fileName))
);
if (SD.MessageService.AskQuestion(message, StringParser.Parse("${res:MainWindow.DialogName}"))) {
if (File.Exists(fileName)) {
file.ReloadFromDisk();
}
} else {
file.MakeDirty();
}
}
queue.Clear();
}
} finally {
currentlyReloading = false;
}
}
public static void CancelReloadQueue()
{
lock (queue) {
queue.Clear();
}
}
#endregion
}
}

Loading…
Cancel
Save