Workspace.h header
#include <ew/app/Workspace.h>
Namespace ew::app
BundleEnvironment struct
struct ew::app::BundleEnvironment
Where a .ewriter single-file project's machinery lives on this machine: the root under which managed working copies are kept, where a diverged copy is backed up before the file wins, and the timestamp such a backup is stamped with. Injected so tests never touch the real per-user folders; production uses Workspace::defaultBundleEnvironment().
Members
QString ew::app::BundleEnvironment::workingCopiesRoot
The folder holding every bundle's extracted working copy (see bundleWorkingCopyDir).
QString ew::app::BundleEnvironment::backupsDir
Where a diverged working copy is preserved as a .ewbackup before re-extraction.
QString ew::app::BundleEnvironment::timestamp
The caller-supplied backup timestamp (e.g. "yyyyMMdd-HHmmsszzz"), kept explicit so the outcome is deterministic and testable.
Workspace class
class ew::app::Workspace
The runtime state of one open project: its content graph, its undo/redo history, and the on-disk folder it saves to. This is the seam the UI drives – edits are pushed onto commandStack(), and save() persists the graph and marks the history clean so isModified() can drive autosave and unsaved-changes prompts.
Members
ew::app::Workspace::Workspace()
Creates a workspace over a new, empty project with no save location yet.
ew::app::Workspace::Workspace(std::unique_ptr< ew::core::Project > project, QString directory)
Adopts project (a null pointer becomes a new empty project) and records directory as its save location (empty if it has none yet).
ew::app::Workspace::~Workspace()
Destroys the workspace.
ew::app::Workspace::Workspace(const Workspace &)=delete
Not copyable.
ew::app::Workspace::Workspace(Workspace &&)=delete
Not movable.
Workspace & ew::app::Workspace::operator=(const Workspace &)=delete
Not copyable.
Workspace & ew::app::Workspace::operator=(Workspace &&)=delete
Not movable.
ew::core::Project & ew::app::Workspace::project()
The content graph being edited.
const ew::core::Project & ew::app::Workspace::project() const
Const overload.
ew::core::CommandStack & ew::app::Workspace::commandStack()
The undo/redo history for edits to the project.
const ew::core::CommandStack & ew::app::Workspace::commandStack() const
Const overload.
MountedLibraries & ew::app::Workspace::mountedLibraries()
The libraries this project mounts, loaded and resolved live into the working graph.
const MountedLibraries & ew::app::Workspace::mountedLibraries() const
Const overload.
void ew::app::Workspace::reloadLibraries()
Reloads the mounted libraries from the project's current mount list, resolving their paths against the save location. Call after the mount list or save location changes.
ew::core::Result< void > ew::app::Workspace::save()
Writes the project to its recorded location and marks the history clean. Returns an error if the workspace has no location yet (call saveAs() first).
ew::core::Result< void > ew::app::Workspace::saveAs(const QString &directory)
Writes the project to directory, then records it as the location and marks the history clean. On failure the previous location is left unchanged. After the project is written, every read/write mounted library is flushed back to its own folder, so edits made to a shared library through this project are persisted to it; an error writing a library is returned once the project itself has been saved. Saving a bundle-backed project to a folder is an explicit conversion: the workspace becomes folder-backed and the .ewriter file is no longer written.
ew::core::Result< void > ew::app::Workspace::saveAsBundle(const QString &bundlePath)
Writes the project as the single-file .ewriter bundle at bundlePath: the project is saved into the bundle's managed working copy (wiping a stale copy left by an older file at the same path), packed into the file atomically, and adopted as the save location – from then on every save() (including autosave) repacks the file, so the file is always current after a successful save. On failure the previous location is left unchanged. The one-argument form uses defaultBundleEnvironment().
ew::core::Result< void > ew::app::Workspace::saveAsBundle(const QString &bundlePath, const BundleEnvironment &environment)
As saveAsBundle(bundlePath), but with an explicit environment for the bundle machinery (working copies, divergence backups, backup timestamp) – the testable form.
bool ew::app::Workspace::isModified() const
Returns true if the project has unsaved changes since the last save or load.
void ew::app::Workspace::noteContentEdited()
Records that the project's content changed outside the command stack – specifically prose typed straight into the document editor, which writes the Document body directly rather than through an undoable command. Without this, isModified() would miss such edits and the app could close or autosave-skip with unsaved prose. Marks the history modified until the next save; a no-op-safe call the editor may make on every edit.
bool ew::app::Workspace::hasPath() const
Returns true if the workspace has a save location.
const QString & ew::app::Workspace::directory() const
The folder the project saves to, or an empty string if it has none yet. For a bundle-backed project this is the managed working copy – an implementation detail; user-facing surfaces (recents, title, reload) must use displayPath() instead.
bool ew::app::Workspace::isBundle() const
True when this project is a single-file .ewriter bundle (saves repack the file).
const QString & ew::app::Workspace::bundlePath() const
The absolute .ewriter file path for a bundle-backed project, else empty.
QString ew::app::Workspace::displayPath() const
The user-facing location of this project: the .ewriter file when bundle-backed, else the project folder. THIS is what recents, the window title, and every reload must use – reopening a bundle project via its working directory would silently drop bundle-backing and stop repacking the file on save.
BundleOpenAction ew::app::Workspace::bundleOpenAction() const
What opening the bundle did with its working copy (meaningful only when isBundle()): RecoverWorkingCopy and BackUpThenExtractFresh deserve a user-visible note.
const QString & ew::app::Workspace::bundleRecoveryBackupPath() const
The .ewbackup written when a diverged working copy was set aside on open (see BundleOpenAction::BackUpThenExtractFresh); empty otherwise.
bool ew::app::Workspace::bundleChangedOnDisk() const
A cheap (no file read) probe of whether the .ewriter file's size or modification time differs from the last open/save – the fast pre-check the change watcher uses to skip a full reconcile when only sibling files in the bundle's folder churned. Always false for a folder project. A true result is a hint to reconcile, not proof of a content change.
ProjectMerge ew::app::Workspace::reconcileWithDisk() const
Reconciles the in-memory project against the current on-disk contents of its save folder, three-way merged against the snapshot taken when the project was last loaded or saved. This surfaces changes another process wrote to the folder since – a file-sync client (Dropbox, etc.), a co-author, or a version-control pull – and flags any that conflict with unsaved local edits. It is non-destructive: it reads and compares but writes nothing. Returns an empty ProjectMerge if the workspace has no save location or the in-memory project cannot be serialized for comparison.
BinaryChanges ew::app::Workspace::externalBinaryChanges() const
Reports the project's binary media assets (images, audio, video) that changed on disk since the project was last loaded or saved – added, removed, or replaced by a co-author or sync client. These files are excluded from reconcileWithDisk() because they cannot be line-merged, so this is the companion that lets external asset changes be surfaced. Non-destructive (reads and compares only). Returns no changes when the workspace has no save location.
ew::core::Result< void > ew::app::Workspace::reloadFromDisk()
Re-reads the project from its save location in place, replacing the in-memory graph with what is on disk now and resetting the undo history and reconcile baselines. This is how a long-lived process (the MCP server) adopts changes another writer – the desktop app – made to the same project since it was opened, so its reads reflect disk and its next save cannot clobber those changes. For a bundle project the .ewriter file is re-extracted into the working copy (the server saves after every change, so the copy holds nothing unsaved to lose); a folder project is re-loaded from the folder. UNSAVED in-memory edits are discarded in favour of disk, and because the history is reset undo spans only edits made since the reload. Returns an error – leaving the in-memory project unchanged – when the workspace has no save location, the project file is not currently readable (a writer mid-save; retry), or the reload otherwise fails.
bool ew::app::Workspace::diskChangedSinceLoad() const
Whether the project's save location differs on disk from the state this workspace last loaded or saved – the cheap pre-check a poller (the MCP server, before each tool call) uses to skip a reload when nothing external changed, so its own just-saved edits stay undoable. For a bundle this is the size/mtime probe (bundleChangedOnDisk); for a folder it compares the text snapshot captured at load/save against the folder now (line-ending differences ignored). Always false without a save location.
static ew::core::Result< std::unique_ptr< Workspace > > ew::app::Workspace::open(const QString &path)
Opens the project at path into a new workspace, or returns the load error. This is the one routing door for both project kinds: a .ewriter file (see isProjectBundlePath) is opened through its managed working copy under the default bundle environment, any other path is loaded as a folder-of-text project directory. The returned workspace starts unmodified (isModified() is false).
static ew::core::Result< std::unique_ptr< Workspace > > ew::app::Workspace::open(const QString &path, const BundleEnvironment &environment)
As open(path), but with an explicit environment for the bundle machinery (working copies, divergence backups, backup timestamp) – the testable form; the environment is ignored for a folder path.
static BundleEnvironment ew::app::Workspace::defaultBundleEnvironment(const QString &bundlePath)
The production bundle environment for the bundle at bundlePath: working copies under the per-user app data folder, divergence backups beside the ordinary project backups (grouped by the bundle's name), stamped with the current time.