From 8f9d3926002266ef354d7b9733b7892c27d16d99 Mon Sep 17 00:00:00 2001 From: Colin Grant Date: Mon, 10 Jan 2022 17:22:43 -0700 Subject: [PATCH] No save dialog if another widget shares identical model --- packages/core/src/browser/saveable.ts | 17 ++++++++++++----- .../core/src/browser/shell/application-shell.ts | 4 ++-- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/core/src/browser/saveable.ts b/packages/core/src/browser/saveable.ts index cea603bfaa8f2..5d7a8f88b7fc0 100644 --- a/packages/core/src/browser/saveable.ts +++ b/packages/core/src/browser/saveable.ts @@ -93,7 +93,7 @@ export namespace Saveable { await saveable.save(options); } } - export function apply(widget: Widget): SaveableWidget | undefined { + export function apply(widget: Widget, getOtherSaveables?: () => Array): SaveableWidget | undefined { if (SaveableWidget.is(widget)) { return widget; } @@ -104,8 +104,8 @@ export namespace Saveable { setDirty(widget, saveable.dirty); saveable.onDirtyChanged(() => setDirty(widget, saveable.dirty)); const closeWidget = widget.close.bind(widget); - const closeWithoutSaving: SaveableWidget['closeWithoutSaving'] = async () => { - if (saveable.dirty && saveable.revert) { + const closeWithoutSaving: SaveableWidget['closeWithoutSaving'] = async (doRevert = true) => { + if (doRevert && saveable.dirty && saveable.revert) { await saveable.revert(); } closeWidget(); @@ -119,6 +119,10 @@ export namespace Saveable { closing = true; try { const result = await shouldSave(saveable, () => { + const notLastWithDocument = getOtherSaveables?.().some(otherWidget => otherWidget !== widget && Saveable.get(otherWidget) === saveable); + if (notLastWithDocument) { + return closeWithoutSaving(false).then(() => undefined); + } if (options && options.shouldSave) { return options.shouldSave(); } @@ -128,7 +132,7 @@ export namespace Saveable { if (result) { await Saveable.save(widget); } - await closeWithoutSaving(); + await closeWithoutSaving(result); } } finally { closing = false; @@ -154,7 +158,10 @@ export namespace Saveable { } export interface SaveableWidget extends Widget { - closeWithoutSaving(): Promise; + /** + * @param doRevert whether the saveable should be reverted before being saved. Defaults to `true`. + */ + closeWithoutSaving(doRevert?: boolean): Promise; closeWithSaving(options?: SaveableWidget.CloseOptions): Promise; } export namespace SaveableWidget { diff --git a/packages/core/src/browser/shell/application-shell.ts b/packages/core/src/browser/shell/application-shell.ts index 4167fe7ea1303..b8a59aa417040 100644 --- a/packages/core/src/browser/shell/application-shell.ts +++ b/packages/core/src/browser/shell/application-shell.ts @@ -24,7 +24,7 @@ import { Message } from '@phosphor/messaging'; import { IDragEvent } from '@phosphor/dragdrop'; import { RecursivePartial, Event as CommonEvent, DisposableCollection, Disposable, environment } from '../../common'; import { animationFrame } from '../browser'; -import { Saveable, SaveableWidget, SaveOptions } from '../saveable'; +import { Saveable, SaveableWidget, SaveOptions, SaveableSource } from '../saveable'; import { StatusBarImpl, StatusBarEntry, StatusBarAlignment } from '../status-bar/status-bar'; import { TheiaDockPanel, BOTTOM_AREA_ID, MAIN_AREA_ID } from './theia-dock-panel'; import { SidePanelHandler, SidePanel, SidePanelHandlerFactory } from './side-panel-handler'; @@ -1025,7 +1025,7 @@ export class ApplicationShell extends Widget { } this.tracker.add(widget); this.checkActivation(widget); - Saveable.apply(widget); + Saveable.apply(widget, () => this.widgets.filter((maybeSaveable): maybeSaveable is Widget & SaveableSource => !!Saveable.get(maybeSaveable))); if (ApplicationShell.TrackableWidgetProvider.is(widget)) { for (const toTrack of widget.getTrackableWidgets()) { this.track(toTrack);