diff --git a/SourceGenWPF/MainController.cs b/SourceGenWPF/MainController.cs
index 14b8380..80e909f 100644
--- a/SourceGenWPF/MainController.cs
+++ b/SourceGenWPF/MainController.cs
@@ -606,18 +606,41 @@ namespace SourceGenWPF {
return true;
}
+#if false
+ private class FinishPrepProgress : WorkProgress.IWorker {
+ public string ExtMessages { get; private set; }
+ private MainController mMainCtrl;
+
+ public FinishPrepProgress(MainController mainCtrl) {
+ mMainCtrl = mainCtrl;
+ }
+ public object DoWork(BackgroundWorker worker) {
+ string messages = mMainCtrl.mProject.LoadExternalFiles();
+ mMainCtrl.DoRefreshProject(UndoableChange.ReanalysisScope.CodeAndData);
+ return messages;
+ }
+
+ public void RunWorkerCompleted(object results) {
+ ExtMessages = (string)results;
+ }
+ }
+#endif
+
private void FinishPrep() {
+ CodeLineList = new LineListGen(mProject, mMainWin.CodeDisplayList,
+ mOutputFormatter, mPseudoOpNames);
+
string messages = mProject.LoadExternalFiles();
if (messages.Length != 0) {
- // ProjectLoadIssues isn't quite the right dialog, but it'll do.
+ // ProjectLoadIssues isn't quite the right dialog, but it'll do. This is
+ // purely informative; no decision needs to be made.
ProjectLoadIssues dlg = new ProjectLoadIssues(mMainWin, messages,
ProjectLoadIssues.Buttons.Continue);
dlg.ShowDialog();
}
- CodeLineList = new LineListGen(mProject, mMainWin.CodeDisplayList,
- mOutputFormatter, mPseudoOpNames);
-
+ // Ideally we'd call DoRefreshProject (and LoadExternalFiles) from a progress
+ // dialog, but we're not allowed to update the DisplayList from a different thread.
RefreshProject(UndoableChange.ReanalysisScope.CodeAndData);
// Populate the Symbols list.
@@ -753,6 +776,20 @@ namespace SourceGenWPF {
UpdateSelectionHighlight();
}
+ ///
+ /// Updates all of the specified ListView entries. This is called after minor changes,
+ /// such as editing a comment or renaming a label, that can be handled by regenerating
+ /// selected parts of the DisplayList.
+ ///
+ ///
+ private void RefreshCodeListViewEntries(RangeSet offsetSet) {
+ IEnumerator iter = offsetSet.RangeListIterator;
+ while (iter.MoveNext()) {
+ RangeSet.Range range = iter.Current;
+ CodeLineList.GenerateRange(range.Low, range.High);
+ }
+ }
+
///
/// Refreshes the project after something of substance has changed. Some
/// re-analysis will be done, followed by a complete rebuild of the DisplayList.
@@ -768,6 +805,47 @@ namespace SourceGenWPF {
// reanalysis after many common operations, the program becomes unpleasant to
// use if we miss this goal, and progress bars won't make it less so.
+ if (mProject.FileDataLength > 65536) {
+ try {
+ Mouse.OverrideCursor = Cursors.Wait;
+ DoRefreshProject(reanalysisRequired);
+ } finally {
+ Mouse.OverrideCursor = null;
+ }
+ } else {
+ DoRefreshProject(reanalysisRequired);
+ }
+
+ if (mGenerationLog != null) {
+ //mReanalysisTimer.StartTask("Save _log");
+ //mGenerationLog.WriteToFile(@"C:\Src\WorkBench\SourceGen\TestData\_log.txt");
+ //mReanalysisTimer.EndTask("Save _log");
+
+ if (mShowAnalyzerOutputDialog != null) {
+ mShowAnalyzerOutputDialog.DisplayText = mGenerationLog.WriteToString();
+ }
+ }
+
+ if (FormatDescriptor.DebugCreateCount != 0) {
+ Debug.WriteLine("FormatDescriptor total=" + FormatDescriptor.DebugCreateCount +
+ " prefab=" + FormatDescriptor.DebugPrefabCount + " (" +
+ (FormatDescriptor.DebugPrefabCount * 100) / FormatDescriptor.DebugCreateCount +
+ "%)");
+ }
+ }
+
+ ///
+ /// Refreshes the project after something of substance has changed.
+ ///
+ ///
+ /// Ideally from this point on we can run on a background thread. The tricky part
+ /// is the close relationship between LineListGen and DisplayList -- we can't update
+ /// DisplayList from a background thread. Until that's fixed, putting up a "working..."
+ /// dialog or other UI will be awkward.
+ ///
+ /// Indicates whether reanalysis is required, and
+ /// what level.
+ private void DoRefreshProject(UndoableChange.ReanalysisScope reanalysisRequired) {
// Changing the CPU type or whether undocumented instructions are supported
// invalidates the Formatter's mnemonic cache. We can change these values
// through undo/redo, so we need to check it here.
@@ -780,40 +858,6 @@ namespace SourceGenWPF {
mOutputFormatterCpuDef = mProject.CpuDef;
}
- if (CodeLineList.Count > 40000) {
- try {
- Mouse.OverrideCursor = Cursors.Wait;
- DoRefreshProject(reanalysisRequired);
- } finally {
- Mouse.OverrideCursor = null;
- }
- } else {
- DoRefreshProject(reanalysisRequired);
- }
-
- if (FormatDescriptor.DebugCreateCount != 0) {
- Debug.WriteLine("FormatDescriptor total=" + FormatDescriptor.DebugCreateCount +
- " prefab=" + FormatDescriptor.DebugPrefabCount + " (" +
- (FormatDescriptor.DebugPrefabCount * 100) / FormatDescriptor.DebugCreateCount +
- "%)");
- }
- }
-
- ///
- /// Updates all of the specified ListView entries. This is called after minor changes,
- /// such as editing a comment or renaming a label, that can be handled by regenerating
- /// selected parts of the DisplayList.
- ///
- ///
- private void RefreshCodeListViewEntries(RangeSet offsetSet) {
- IEnumerator iter = offsetSet.RangeListIterator;
- while (iter.MoveNext()) {
- RangeSet.Range range = iter.Current;
- CodeLineList.GenerateRange(range.Low, range.High);
- }
- }
-
- private void DoRefreshProject(UndoableChange.ReanalysisScope reanalysisRequired) {
if (reanalysisRequired != UndoableChange.ReanalysisScope.DisplayOnly) {
mGenerationLog = new CommonUtil.DebugLog();
mGenerationLog.SetMinPriority(CommonUtil.DebugLog.Priority.Debug);
@@ -824,16 +868,6 @@ namespace SourceGenWPF {
mReanalysisTimer.EndTask("Call DisasmProject.Analyze()");
}
- if (mGenerationLog != null) {
- //mReanalysisTimer.StartTask("Save _log");
- //mGenerationLog.WriteToFile(@"C:\Src\WorkBench\SourceGen\TestData\_log.txt");
- //mReanalysisTimer.EndTask("Save _log");
-
- if (mShowAnalyzerOutputDialog != null) {
- mShowAnalyzerOutputDialog.DisplayText = mGenerationLog.WriteToString();
- }
- }
-
mReanalysisTimer.StartTask("Generate DisplayList");
CodeLineList.GenerateAll();
mReanalysisTimer.EndTask("Generate DisplayList");
@@ -903,13 +937,14 @@ namespace SourceGenWPF {
}
///
- /// Handles opening an existing project, given a pathname to the project file.
+ /// Handles opening an existing project, given a full pathname to the project file.
///
private void DoOpenFile(string projPathName) {
Debug.WriteLine("DoOpenFile: " + projPathName);
Debug.Assert(mProject == null);
if (!File.Exists(projPathName)) {
+ // Should only happen for projects in "recents".
string msg = string.Format(Res.Strings.ERR_FILE_NOT_FOUND_FMT, projPathName);
MessageBox.Show(msg, Res.Strings.ERR_FILE_GENERIC_CAPTION,
MessageBoxButton.OK, MessageBoxImage.Error);
@@ -1188,11 +1223,8 @@ namespace SourceGenWPF {
mProjectPathName = null;
mTargetHighlightIndex = -1;
- // Clear this to release the memory.
- mMainWin.CodeDisplayList.Clear();
-
- mMainWin.InfoPanelContents = string.Empty;
mMainWin.ShowCodeListView = false;
+ mMainWin.ProjectClosing();
mGenerationLog = null;
diff --git a/SourceGenWPF/WpfGui/MainWindow.xaml.cs b/SourceGenWPF/WpfGui/MainWindow.xaml.cs
index 0b987b1..18cf433 100644
--- a/SourceGenWPF/WpfGui/MainWindow.xaml.cs
+++ b/SourceGenWPF/WpfGui/MainWindow.xaml.cs
@@ -388,6 +388,22 @@ namespace SourceGenWPF.WpfGui {
}
}
+ ///
+ /// Cleans up state when MainController decides to close the project.
+ ///
+ public void ProjectClosing() {
+ // Clear this to release the memory.
+ CodeDisplayList.Clear();
+
+ InfoPanelContents = string.Empty;
+
+ // If you open a new project while one is already open, the ListView apparently
+ // doesn't reset certain state, possibly because it's never asked to draw after
+ // the list is cleared. This results in the new project being open at the same
+ // line as the previous project. This is a little weird, so we reset it here.
+ CodeListView_SetTopIndex(0);
+ }
+
///
/// Catch mouse-down events so we can treat the fourth mouse button as "back".
///
diff --git a/SourceGenWPF/WpfGui/WorkProgress.xaml.cs b/SourceGenWPF/WpfGui/WorkProgress.xaml.cs
index f744405..bbe91fa 100644
--- a/SourceGenWPF/WpfGui/WorkProgress.xaml.cs
+++ b/SourceGenWPF/WpfGui/WorkProgress.xaml.cs
@@ -126,7 +126,7 @@ namespace SourceGenWPF.WpfGui {
DialogResult = false;
}
} else if (e.Error != null) {
- // Unexpected -- shell command execution shouldn't throw exceptions.
+ // Unexpected; success/failure should be passed through e.Result.
MessageBox.Show(e.Error.ToString(), Res.Strings.OPERATION_FAILED,
MessageBoxButton.OK, MessageBoxImage.Error);
DialogResult = false;