mirror of
https://github.com/fadden/6502bench.git
synced 2024-10-31 19:04:44 +00:00
Auto-save, part 3 (of 3)
Added the recovery file check when a project is opened, and the GUI elements for choosing which file to use. If a recovery file exists but can't be opened, presumably because it's open by another process, offer to open the project read-only. (This is a generally good idea, but we don't hold the project file open in normal usage, so it only works when auto-save is enabled.) After making a choice, auto-save is disabled until the first manual save. One thing we don't do: if we find a recovery file, but auto-save is disabled, the recovery file won't be deleted after the user makes a choice. This might be a feature. Updated documentation. (issue #161)
This commit is contained in:
parent
1b2353c259
commit
fca742e890
@ -727,12 +727,17 @@ namespace SourceGen {
|
||||
|
||||
#region Auto-save
|
||||
|
||||
private string mRecoveryPathName = string.Empty;
|
||||
private Stream mRecoveryStream = null;
|
||||
private const string RECOVERY_EXT_ADD = "_rec";
|
||||
private const string RECOVERY_EXT = ProjectFile.FILENAME_EXT + RECOVERY_EXT_ADD;
|
||||
|
||||
private DispatcherTimer mAutoSaveTimer = null;
|
||||
private DateTime mLastEditWhen = DateTime.Now;
|
||||
private DateTime mLastAutoSaveWhen = DateTime.Now;
|
||||
private string mRecoveryPathName = string.Empty; // path to recovery file, or empty str
|
||||
private Stream mRecoveryStream = null; // stream for recovery file, or null
|
||||
|
||||
private DispatcherTimer mAutoSaveTimer = null; // auto-save timer, may be disabled
|
||||
private DateTime mLastEditWhen = DateTime.Now; // timestamp of last user edit
|
||||
private DateTime mLastAutoSaveWhen = DateTime.Now; // timestamp of last auto-save
|
||||
|
||||
private bool mAutoSaveDeferred = false;
|
||||
|
||||
|
||||
/// <summary>
|
||||
@ -827,14 +832,33 @@ namespace SourceGen {
|
||||
/// Creates or deletes the recovery file, based on the current app settings.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// This is called when a new project is created, an existing project is opened, the
|
||||
/// app settings are updated, or Save As is used to change the project name.
|
||||
/// <para>This is called when:</para>
|
||||
/// <list type="bullet">
|
||||
/// <item>a new project is created</item>
|
||||
/// <item>an existing project is opened</item>
|
||||
/// <item>app settings are updated</item>
|
||||
/// <item>Save As is used to change the project path</item>
|
||||
/// <item>the project is saved for the first time after a recovery file decision (i.e.
|
||||
/// while mAutoSaveDeferred is true)</item>
|
||||
/// </list>
|
||||
/// </remarks>
|
||||
private void RefreshRecoveryFile() {
|
||||
if (mProject == null) {
|
||||
// Project not open, nothing to do.
|
||||
return;
|
||||
}
|
||||
if (mProject.IsReadOnly) {
|
||||
// Changes cannot be made, so there's no need for a recovery file. Also, we
|
||||
// might be in read-only mode because the project is already open and has a
|
||||
// recovery file opened by another process.
|
||||
Debug.WriteLine("Recovery: project is read-only, not creating recovery file");
|
||||
Debug.Assert(mRecoveryStream == null);
|
||||
return;
|
||||
}
|
||||
if (mAutoSaveDeferred) {
|
||||
Debug.WriteLine("Recovery: auto-save deferred, not touching recovery file");
|
||||
return;
|
||||
}
|
||||
|
||||
int interval = AppSettings.Global.GetInt(AppSettings.PROJ_AUTO_SAVE_INTERVAL, 0);
|
||||
if (interval <= 0) {
|
||||
@ -855,7 +879,7 @@ namespace SourceGen {
|
||||
// case auto-save was previously disabled.
|
||||
mLastAutoSaveWhen = mLastEditWhen.AddSeconds(-1);
|
||||
|
||||
string pathName = GenerateRecoveryPathName();
|
||||
string pathName = GenerateRecoveryPathName(mProjectPathName);
|
||||
if (!string.IsNullOrEmpty(mRecoveryPathName) && pathName == mRecoveryPathName) {
|
||||
// File is open and the filename hasn't changed. Nothing to do.
|
||||
Debug.Assert(mRecoveryStream != null);
|
||||
@ -866,18 +890,18 @@ namespace SourceGen {
|
||||
"' in favor of '" + pathName + "'");
|
||||
DiscardRecoveryFile();
|
||||
}
|
||||
Debug.WriteLine("Recovery: opening '" + pathName + "'");
|
||||
Debug.WriteLine("Recovery: creating '" + pathName + "'");
|
||||
PrepareRecoveryFile();
|
||||
}
|
||||
mAutoSaveTimer.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private string GenerateRecoveryPathName() {
|
||||
if (string.IsNullOrEmpty(mProjectPathName)) {
|
||||
private static string GenerateRecoveryPathName(string pathName) {
|
||||
if (string.IsNullOrEmpty(pathName)) {
|
||||
return string.Empty;
|
||||
} else {
|
||||
return mProjectPathName + "_rec";
|
||||
return pathName + RECOVERY_EXT_ADD;
|
||||
}
|
||||
}
|
||||
|
||||
@ -889,7 +913,7 @@ namespace SourceGen {
|
||||
Debug.Assert(mRecoveryStream == null);
|
||||
Debug.Assert(string.IsNullOrEmpty(mRecoveryPathName));
|
||||
|
||||
string pathName = GenerateRecoveryPathName();
|
||||
string pathName = GenerateRecoveryPathName(mProjectPathName);
|
||||
try {
|
||||
mRecoveryStream = new FileStream(pathName, FileMode.OpenOrCreate, FileAccess.Write);
|
||||
mRecoveryPathName = pathName;
|
||||
@ -924,6 +948,64 @@ namespace SourceGen {
|
||||
mAutoSaveTimer.Stop();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Asks the user if they want to use the recovery file, if one is present and non-empty.
|
||||
/// Both files must exist.
|
||||
/// </summary>
|
||||
/// <param name="projPathName">Path to project file we're trying to open</param>
|
||||
/// <param name="recoveryPath">Path to recovery file.</param>
|
||||
/// <param name="pathToUse">Result: path the user wishes to use. If we didn't ask the
|
||||
/// user to choose, because the recovery file was empty or in use by another process,
|
||||
/// this will be an empty string.</param>
|
||||
/// <param name="asReadOnly">Result: true if project should be opened read-only.</param>
|
||||
/// <returns>False if the user cancelled the operation, true to continue.</returns>
|
||||
private bool HandleRecoveryChoice(string projPathName, string recoveryPath,
|
||||
out string pathToUse, out bool asReadOnly) {
|
||||
pathToUse = string.Empty;
|
||||
asReadOnly = false;
|
||||
|
||||
try {
|
||||
using (FileStream stream = new FileStream(recoveryPath, FileMode.Open,
|
||||
FileAccess.ReadWrite, FileShare.None)) {
|
||||
if (stream.Length == 0) {
|
||||
// Recovery file exists, but is empty and not open by another process.
|
||||
// Ignore it. (We could delete it here, but there's no need.)
|
||||
Debug.WriteLine("Recovery: found existing zero-length file (ignoring)");
|
||||
return true;
|
||||
}
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
// Unable to open recovery file. This is probably happening because another
|
||||
// process has the file open.
|
||||
Debug.WriteLine("Unable to open recovery file: " + ex.Message);
|
||||
MessageBoxResult mbr = MessageBox.Show(mMainWin,
|
||||
"The project has a recovery file that can't be opened, possibly because the " +
|
||||
"project is currently open by another copy of the application. Do you wish " +
|
||||
"to open the file read-only?",
|
||||
"Unable to Open", MessageBoxButton.OKCancel, MessageBoxImage.Hand);
|
||||
if (mbr == MessageBoxResult.OK) {
|
||||
asReadOnly = true;
|
||||
return true;
|
||||
} else {
|
||||
asReadOnly = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
RecoveryChoice dlg = new RecoveryChoice(mMainWin, projPathName, recoveryPath);
|
||||
if (dlg.ShowDialog() != true) {
|
||||
return false;
|
||||
}
|
||||
if (dlg.UseRecoveryFile) {
|
||||
Debug.WriteLine("Recovery: user chose recovery file");
|
||||
pathToUse = recoveryPath;
|
||||
} else {
|
||||
Debug.WriteLine("Recovery: user chose project file");
|
||||
pathToUse = projPathName;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
#endregion Auto-save
|
||||
|
||||
|
||||
@ -1342,11 +1424,33 @@ namespace SourceGen {
|
||||
DisasmProject newProject = new DisasmProject();
|
||||
newProject.UseMainAppDomainForPlugins = UseMainAppDomainForPlugins;
|
||||
|
||||
// Is there a recovery file?
|
||||
mAutoSaveDeferred = false;
|
||||
string recoveryPath = GenerateRecoveryPathName(projPathName);
|
||||
string openPath = projPathName;
|
||||
if (File.Exists(recoveryPath)) {
|
||||
// Found a recovery file.
|
||||
bool ok = HandleRecoveryChoice(projPathName, recoveryPath, out string pathToUse,
|
||||
out bool asReadOnly);
|
||||
if (!ok) {
|
||||
// Open has been cancelled.
|
||||
return;
|
||||
}
|
||||
if (!string.IsNullOrEmpty(pathToUse)) {
|
||||
// One was chosen. This should be the case unless the recovery file was
|
||||
// empty, or was open by a different process.
|
||||
Debug.WriteLine("Open: user chose '" + pathToUse + "', deferring auto-save");
|
||||
openPath = pathToUse;
|
||||
mAutoSaveDeferred = true;
|
||||
}
|
||||
newProject.IsReadOnly |= asReadOnly;
|
||||
}
|
||||
|
||||
// Deserialize the project file. I want to do this before loading the data file
|
||||
// in case we decide to store the data file name in the project (e.g. the data
|
||||
// file is a disk image or zip archive, and we need to know which part(s) to
|
||||
// extract).
|
||||
if (!ProjectFile.DeserializeFromFile(projPathName, newProject,
|
||||
if (!ProjectFile.DeserializeFromFile(openPath, newProject,
|
||||
out FileLoadReport report)) {
|
||||
// Should probably use a less-busy dialog for something simple like
|
||||
// "permission denied", but the open file dialog handles most simple
|
||||
@ -1363,11 +1467,16 @@ namespace SourceGen {
|
||||
// locate it manually, repeating the process until successful or canceled.
|
||||
const string UNKNOWN_FILE = "UNKNOWN";
|
||||
string dataPathName;
|
||||
if (projPathName.Length <= ProjectFile.FILENAME_EXT.Length) {
|
||||
dataPathName = UNKNOWN_FILE;
|
||||
} else {
|
||||
if (projPathName.EndsWith(ProjectFile.FILENAME_EXT,
|
||||
StringComparison.InvariantCultureIgnoreCase)) {
|
||||
dataPathName = projPathName.Substring(0,
|
||||
projPathName.Length - ProjectFile.FILENAME_EXT.Length);
|
||||
} else if (projPathName.EndsWith(RECOVERY_EXT,
|
||||
StringComparison.InvariantCultureIgnoreCase)) {
|
||||
dataPathName = projPathName.Substring(0,
|
||||
projPathName.Length - RECOVERY_EXT.Length);
|
||||
} else {
|
||||
dataPathName = UNKNOWN_FILE;
|
||||
}
|
||||
byte[] fileData;
|
||||
while ((fileData = FindValidDataFile(ref dataPathName, newProject,
|
||||
@ -1391,7 +1500,7 @@ namespace SourceGen {
|
||||
return;
|
||||
}
|
||||
|
||||
newProject.IsReadOnly = dlg.WantReadOnly;
|
||||
newProject.IsReadOnly |= dlg.WantReadOnly;
|
||||
}
|
||||
|
||||
mProject = newProject;
|
||||
@ -1539,6 +1648,7 @@ namespace SourceGen {
|
||||
}
|
||||
|
||||
private bool DoSave(string pathName) {
|
||||
Debug.Assert(!mProject.IsReadOnly); // save commands should be disabled
|
||||
Debug.WriteLine("SAVING " + pathName);
|
||||
if (!ProjectFile.SerializeToFile(mProject, pathName, out string errorMessage)) {
|
||||
MessageBox.Show(Res.Strings.ERR_PROJECT_SAVE_FAIL + ": " + errorMessage,
|
||||
@ -1560,6 +1670,11 @@ namespace SourceGen {
|
||||
// Seems like a good time to save this off too.
|
||||
SaveAppSettings();
|
||||
|
||||
if (mAutoSaveDeferred) {
|
||||
mAutoSaveDeferred = false;
|
||||
RefreshRecoveryFile();
|
||||
}
|
||||
|
||||
// The project file is saved, no need to auto-save for a while.
|
||||
ResetAutoSaveTimer();
|
||||
|
||||
|
@ -238,6 +238,9 @@
|
||||
<Compile Include="UndoableChange.cs" />
|
||||
<Compile Include="DisplayListSelection.cs" />
|
||||
<Compile Include="WeakSymbolRef.cs" />
|
||||
<Compile Include="WpfGui\RecoveryChoice.xaml.cs">
|
||||
<DependentUpon>RecoveryChoice.xaml</DependentUpon>
|
||||
</Compile>
|
||||
<Compile Include="WpfGui\ShowWireframeAnimation.xaml.cs">
|
||||
<DependentUpon>ShowWireframeAnimation.xaml</DependentUpon>
|
||||
</Compile>
|
||||
@ -476,6 +479,10 @@
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WpfGui\RecoveryChoice.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
</Page>
|
||||
<Page Include="WpfGui\ShowWireframeAnimation.xaml">
|
||||
<SubType>Designer</SubType>
|
||||
<Generator>MSBuild:Compile</Generator>
|
||||
|
87
SourceGen/WpfGui/RecoveryChoice.xaml
Normal file
87
SourceGen/WpfGui/RecoveryChoice.xaml
Normal file
@ -0,0 +1,87 @@
|
||||
<!--
|
||||
Copyright 2024 faddenSoft
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
|
||||
<Window x:Class="SourceGen.WpfGui.RecoveryChoice"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:local="clr-namespace:SourceGen.WpfGui"
|
||||
mc:Ignorable="d"
|
||||
Title="Use Recovery File?"
|
||||
SizeToContent="Height" Width="500" MinWidth="500" ResizeMode="CanResizeWithGrip"
|
||||
ShowInTaskbar="False" WindowStartupLocation="CenterOwner"
|
||||
ContentRendered="Window_ContentRendered">
|
||||
|
||||
<Grid Margin="8">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="*"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<TextBlock Grid.Row="0" TextWrapping="Wrap"
|
||||
Text="A recovery file, created by the auto-save feature, was found. Please choose which you would like to use."/>
|
||||
|
||||
<Grid Grid.Row="1" Margin="0,8,0,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!--<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="0,0,0,4"
|
||||
Text="Or leave the existing file alone:"/>-->
|
||||
<Button Name="projectButton" Grid.Column="0" Grid.Row="1" Grid.RowSpan="4"
|
||||
Width="80" Height="60" Margin="0,0,8,0" HorizontalAlignment="Left" BorderThickness="1"
|
||||
Content="Project File" Click="ProjectButton_Click"/>
|
||||
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding ProjPathName, FallbackValue=ProjPath}" FontWeight="Bold"/>
|
||||
<TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding ProjModWhen, FallbackValue=Modified:yesterday}"/>
|
||||
<TextBlock Grid.Column="1" Grid.Row="3" Text="{Binding ProjLength, FallbackValue=len:1234kB}"/>
|
||||
</Grid>
|
||||
|
||||
<Grid Grid.Row="2" Margin="0,8,0,0">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
<ColumnDefinition Width="*"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
<!--<TextBlock Grid.Column="0" Grid.Row="0" Grid.ColumnSpan="2" Margin="0,0,0,4"
|
||||
Text="You can use the project file:"/>-->
|
||||
<Button Name="recoveryButton" Grid.Column="0" Grid.Row="1" Grid.RowSpan="4"
|
||||
Width="80" Height="60" Margin="0,0,8,0" HorizontalAlignment="Left" BorderThickness="1"
|
||||
Content="Recovery File" Click="RecoveryButton_Click"/>
|
||||
<TextBlock Grid.Column="1" Grid.Row="1" Text="{Binding RecovPathName, FallbackValue=RecovPath}" FontWeight="Bold"/>
|
||||
<TextBlock Grid.Column="1" Grid.Row="2" Text="{Binding RecovModWhen, FallbackValue=Modified:today}"/>
|
||||
<TextBlock Grid.Column="1" Grid.Row="3" Text="{Binding RecovLength, FallbackValue=len:2345kB}"/>
|
||||
</Grid>
|
||||
|
||||
<DockPanel Grid.Row="3" Margin="0,16,0,0" LastChildFill="False">
|
||||
<Button DockPanel.Dock="Right" Name="cancelButton" Content="Cancel" IsCancel="True"
|
||||
Width="70" Margin="4,0,4,0"/>
|
||||
</DockPanel>
|
||||
</Grid>
|
||||
</Window>
|
111
SourceGen/WpfGui/RecoveryChoice.xaml.cs
Normal file
111
SourceGen/WpfGui/RecoveryChoice.xaml.cs
Normal file
@ -0,0 +1,111 @@
|
||||
/*
|
||||
* Copyright 2024 faddenSoft
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Windows;
|
||||
using System.Windows.Media;
|
||||
|
||||
namespace SourceGen.WpfGui {
|
||||
/// <summary>
|
||||
/// Present a choice between the project file and the recovery file.
|
||||
/// </summary>
|
||||
public partial class RecoveryChoice : Window {
|
||||
/// <summary>
|
||||
/// Dialog result: true if the recovery file was selected.
|
||||
/// </summary>
|
||||
public bool UseRecoveryFile { get; private set; }
|
||||
|
||||
//
|
||||
// Dialog strings.
|
||||
//
|
||||
|
||||
public string ProjPathName { get; set; }
|
||||
public string ProjModWhen { get; set; }
|
||||
public string ProjLength { get; set; }
|
||||
public string RecovPathName { get; set; }
|
||||
public string RecovModWhen { get; set; }
|
||||
public string RecovLength { get; set; }
|
||||
|
||||
|
||||
public RecoveryChoice(Window parent, string projPathName, string recoveryPathName) {
|
||||
InitializeComponent();
|
||||
Owner = parent;
|
||||
DataContext = this;
|
||||
|
||||
string modWhenStr, lenStr;
|
||||
GetFileInfo(projPathName, out DateTime projModWhen, out modWhenStr, out lenStr);
|
||||
ProjPathName = projPathName;
|
||||
ProjModWhen = modWhenStr;
|
||||
ProjLength = lenStr;
|
||||
GetFileInfo(recoveryPathName, out DateTime recovModWhen, out modWhenStr, out lenStr);
|
||||
RecovPathName = recoveryPathName;
|
||||
RecovModWhen = modWhenStr;
|
||||
RecovLength = lenStr;
|
||||
|
||||
if (projModWhen >= recovModWhen) {
|
||||
projectButton.BorderBrush = Brushes.Green;
|
||||
projectButton.BorderThickness = new Thickness(2);
|
||||
} else {
|
||||
recoveryButton.BorderBrush = Brushes.Green;
|
||||
recoveryButton.BorderThickness = new Thickness(2);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads and formats some basic information about the file.
|
||||
/// </summary>
|
||||
/// <param name="pathName">Pathname to file.</param>
|
||||
/// <param name="modWhen">Result: modification date.</param>
|
||||
/// <param name="modWhenStr">Result: formatted modification date.</param>
|
||||
/// <param name="lenStr">Result: formatted file length.</param>
|
||||
private static void GetFileInfo(string pathName, out DateTime modWhen,
|
||||
out string modWhenStr, out string lenStr) {
|
||||
try {
|
||||
FileInfo fi = new FileInfo(pathName);
|
||||
modWhen = fi.LastWriteTime;
|
||||
modWhenStr = "Modified: " + modWhen.ToString("G");
|
||||
long len = fi.Length;
|
||||
if (len >= 4096) {
|
||||
lenStr = "Length: " + (len / 1024.0).ToString("F2") + " kB";
|
||||
} else {
|
||||
lenStr = "Length: " + len + " bytes";
|
||||
}
|
||||
} catch (Exception ex) {
|
||||
modWhenStr = "file error";
|
||||
lenStr = ex.Message;
|
||||
modWhen = DateTime.Now;
|
||||
}
|
||||
}
|
||||
|
||||
private void Window_ContentRendered(object sender, EventArgs e) {
|
||||
// Don't allow the window to be resized smaller than its initial size in width.
|
||||
MinWidth = ActualWidth;
|
||||
// Don't allow the height to be changed.
|
||||
MinHeight = ActualHeight;
|
||||
MaxHeight = ActualHeight;
|
||||
}
|
||||
|
||||
private void ProjectButton_Click(object sender, RoutedEventArgs e) {
|
||||
UseRecoveryFile = false;
|
||||
DialogResult = true;
|
||||
}
|
||||
|
||||
private void RecoveryButton_Click(object sender, RoutedEventArgs e) {
|
||||
UseRecoveryFile = true;
|
||||
DialogResult = true;
|
||||
}
|
||||
}
|
||||
}
|
@ -73,6 +73,7 @@ using the <samp>Help > Help</samp> menu item or by hitting
|
||||
<ul>
|
||||
<li><a href="mainwin.html#starting-new">Starting a New Project</a></li>
|
||||
<li><a href="mainwin.html#opening">Opening an Existing Project</a></li>
|
||||
<li><a href="mainwin.html#saving">Saving a Project</a></li>
|
||||
<li><a href="mainwin.html#working">Working With a Project</a>
|
||||
<ul>
|
||||
<li><a href="mainwin.html#code-list">Code List</a></li>
|
||||
|
@ -34,13 +34,13 @@ project.</p>
|
||||
<p><strong>NOTE:</strong> Support for very large 65816 programs is
|
||||
incomplete. The maximum size for a data file is limited to 1 MiB.</p>
|
||||
|
||||
<p>The first time you save the project (with <samp>File > Save</samp>),
|
||||
you will be prompted for the project name. It's best to use the
|
||||
data file's name with "<samp>.dis65</samp>" added, so this will be set as
|
||||
the default. The data file's name is not stored in the project file,
|
||||
so if you pick a different name, or save the project in a different
|
||||
directory, you will have to select the data file manually whenever you
|
||||
open the project.</p>
|
||||
<p>The application will ask you to save the new project to a file.
|
||||
It's best to use the data file's name with "<samp>.dis65</samp>" added,
|
||||
so this will be set as the default. The data file's name is not stored
|
||||
in the project file, so if you pick a different name, or save the project
|
||||
in a different directory, you will have to select the data file manually
|
||||
whenever you open the project. (You can cancel the dialog to proceed
|
||||
without creating a project file, but certain features will be unavailable.)</p>
|
||||
|
||||
|
||||
<h2 id="opening">Opening an Existing Project</h2>
|
||||
@ -68,6 +68,30 @@ in the application settings. You can access them from
|
||||
that open the two most-recently-opened projects will be available.</p>
|
||||
|
||||
|
||||
<h2 id="saving">Saving a Project</h2>
|
||||
|
||||
<p>You can save your project with <samp>File > Save</samp>, or by
|
||||
hitting <kbd class="key">Ctrl+S</kbd>. To save the project to a different
|
||||
file, use <samp>File > Save As</samp>, but bear in mind that the data
|
||||
file is expected to have the same name as the project file, minus the
|
||||
".dis65" extension.</p>
|
||||
|
||||
<p>If auto-save is enabled in the application settings, a "recovery" file
|
||||
will be created and updated periodically. This file has the same name as
|
||||
the project file, but with "_rec" added. The recovery file is only updated
|
||||
if the project has been edited but not saved, and the auto-save timer is reset
|
||||
whenever the project is manually saved, so if you're diligent about saving
|
||||
your work the file may never be written to.</p>
|
||||
|
||||
<p>When a project is opened, if a recovery file exists, the file will be
|
||||
checked to see if it's empty or open in a different process. In the former
|
||||
case it will be ignored, in the latter you will be asked if you want to
|
||||
open the project read-only. If the file is non-empty and not in use, you
|
||||
will be given the opportunity to choose which file to use. After making a
|
||||
choice, the auto-save feature will be disabled until the first manual save
|
||||
is made.</p>
|
||||
|
||||
|
||||
<h2 id="working">Working With a Project</h2>
|
||||
|
||||
<p>The main project window is divided into five areas:</p>
|
||||
|
@ -81,6 +81,11 @@ from the system theme, but the disassembly list uses a custom style. You
|
||||
can change the rest of the UI from the Windows display "personalization"
|
||||
controls.)</p>
|
||||
|
||||
<p>The <samp>auto-save interval</samp> selection determines the frequency
|
||||
of saves to the recovery file. Setting it to <samp>disabled</samp> will
|
||||
disable the feature entirely, and prevent recovery files from being created
|
||||
(though they will still be checked for when projects are opened).</p>
|
||||
|
||||
|
||||
<h3 id="appset-textdelim">Text Delimiters</h3>
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user