mirror of
https://github.com/ajisaacs/OpenNest.git
synced 2026-11-14 05:45:07 -05:00
NestTabs.SaveAs writes the tab's nest, makes the file its file and name, and clears its unsaved mark; a write that fails throws and changes nothing. ExportCopy writes the nest without touching its file, name or unsaved mark. Both refuse, before writing anything, a file another open tab shows (so one file never has two tabs) and a tab that has been closed; Export also refuses the tab's own file, which only Save may write. Refusals are a SaveTargetRefusedException whose message says what to do. SavePath is the file Save writes without asking: only one saved to this session, as in the WinForms app, so a nest that was only opened asks for a file on its first Save. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
116 lines
4.6 KiB
C#
116 lines
4.6 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using OpenNest.Data;
|
|
using OpenNest.Engine.BestFit;
|
|
using OpenNest.IO;
|
|
using OpenNest.Undo;
|
|
|
|
namespace OpenNest
|
|
{
|
|
public class Document
|
|
{
|
|
public Nest Nest { get; set; }
|
|
|
|
/// <summary>
|
|
/// This document's undo history: whole-nest states, reset with the first one when the
|
|
/// nest window opens. Saving marks a save point; it never clears the history.
|
|
/// </summary>
|
|
public UndoHistory<NestUndoState> History { get; } = new();
|
|
|
|
public DateTime LastSaveDate { get; private set; }
|
|
|
|
public string LastSavePath { get; private set; }
|
|
|
|
private readonly NestSaveSession remoteSession = new();
|
|
|
|
public Guid RemoteId => remoteSession.RemoteId;
|
|
public Guid PendingCreateId => remoteSession.PendingCreateId;
|
|
public bool PendingCreateRequiresReconciliation => remoteSession.PendingCreateId != Guid.Empty && remoteSession.RequiresReload;
|
|
public bool PendingCreateWasCopy => remoteSession.PendingCreateWasCopy;
|
|
public bool IsFirstDatabaseSave(string serverUrl) => remoteSession.IsFirstSave(serverUrl);
|
|
|
|
/// <summary>
|
|
/// A duplicate name the user already accepted in Nest Info, so the first Save
|
|
/// does not ask about it again.
|
|
/// </summary>
|
|
public string AcceptedDuplicateName { get; set; }
|
|
|
|
public void BindRemote(Guid id, string serverUrl) => remoteSession.Bind(id, serverUrl);
|
|
|
|
public void BindRemote(Guid id, string serverUrl, int revision) => remoteSession.Bind(id, serverUrl, revision);
|
|
|
|
public Task<NestRecord> ReconcilePendingCreateAsync(INestRepository repository, string serverUrl,
|
|
CancellationToken cancellationToken = default) =>
|
|
remoteSession.ReconcilePendingCreateAsync(repository, serverUrl, cancellationToken);
|
|
|
|
public int RemoteRevision => remoteSession.Revision;
|
|
|
|
public string Name => Nest?.Name;
|
|
|
|
public bool HasSavePath => File.Exists(LastSavePath);
|
|
|
|
/// <summary>
|
|
/// Saves to <paramref name="path"/>. A failed write throws and leaves the nest's name and
|
|
/// save path as they were, and any file already at the path untouched.
|
|
/// </summary>
|
|
public void SaveAs(string path)
|
|
{
|
|
var previousName = Nest.Name;
|
|
Nest.Name = Path.GetFileNameWithoutExtension(path);
|
|
try
|
|
{
|
|
var writer = new NestWriter(Nest) { BestFitStore = BestFitCacheStore.Shared };
|
|
if (!writer.Write(path))
|
|
throw new IOException($"The nest could not be written to {path}.");
|
|
}
|
|
catch
|
|
{
|
|
Nest.Name = previousName;
|
|
throw;
|
|
}
|
|
|
|
LastSaveDate = DateTime.Now;
|
|
LastSavePath = path;
|
|
if (History.Current != null)
|
|
History.MarkSaved();
|
|
}
|
|
|
|
/// <summary>
|
|
/// Writes a copy of the nest to <paramref name="path"/>. The nest's name, save path,
|
|
/// server identity and undo save point stay as they were (the writer still stamps its
|
|
/// last-modified date, as every save does).
|
|
/// </summary>
|
|
public void ExportCopy(string path)
|
|
{
|
|
// A write that fails throws and leaves any file already at the path as it was.
|
|
new NestWriter(Nest) { BestFitStore = BestFitCacheStore.Shared }.Write(path);
|
|
}
|
|
|
|
/// <summary>Serializes the current nest to a .nest archive in memory.</summary>
|
|
public byte[] Serialize()
|
|
{
|
|
using var stream = new MemoryStream();
|
|
new NestWriter(Nest) { BestFitStore = BestFitCacheStore.Shared }.Write(stream);
|
|
return stream.ToArray();
|
|
}
|
|
|
|
/// <summary>Uploads this nest, preserving its server identity only on success.</summary>
|
|
public async Task<NestRecord> SaveToDatabaseAsync(
|
|
INestRepository repository, string serverUrl, bool saveCopy = false,
|
|
CancellationToken cancellationToken = default)
|
|
{
|
|
var bytes = Serialize();
|
|
// The save point is the state serialized here, unless an edit was recorded since.
|
|
var state = History.Current;
|
|
var saved = await remoteSession.SaveAsync(
|
|
repository, serverUrl, Nest, bytes, saveCopy, cancellationToken);
|
|
LastSaveDate = DateTime.Now;
|
|
if (state != null && ReferenceEquals(History.Current, state))
|
|
History.MarkSaved();
|
|
return saved;
|
|
}
|
|
}
|
|
}
|