diff --git a/packages/editor-preview/src/browser/editor-preview-widget.ts b/packages/editor-preview/src/browser/editor-preview-widget.ts index b08f39c63ab64..9d2002f34f554 100644 --- a/packages/editor-preview/src/browser/editor-preview-widget.ts +++ b/packages/editor-preview/src/browser/editor-preview-widget.ts @@ -14,22 +14,17 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** -import { Message } from '@theia/core/shared/@phosphor/messaging'; -import { DockPanel, TabBar, Widget, PINNED_CLASS } from '@theia/core/lib/browser'; +import { TabBar, Widget, PINNED_CLASS } from '@theia/core/lib/browser'; import { EditorWidget, TextEditor } from '@theia/editor/lib/browser'; import { Disposable, DisposableCollection, Emitter, SelectionService, UNTITLED_SCHEME } from '@theia/core/lib/common'; -import { find } from '@theia/core/shared/@phosphor/algorithm'; const PREVIEW_TITLE_CLASS = 'theia-editor-preview-title-unpinned'; export class EditorPreviewWidget extends EditorWidget { protected _isPreview = false; - protected lastTabbar: TabBar | undefined; protected readonly onDidChangePreviewStateEmitter = new Emitter(); readonly onDidChangePreviewState = this.onDidChangePreviewStateEmitter.event; - protected readonly toDisposeOnLocationChange = new DisposableCollection(); - get isPreview(): boolean { return this._isPreview; } @@ -40,7 +35,6 @@ export class EditorPreviewWidget extends EditorWidget { ) { super(editor, selectionService); this.toDispose.push(this.onDidChangePreviewStateEmitter); - this.toDispose.push(this.toDisposeOnLocationChange); } initializePreview(): void { @@ -66,34 +60,17 @@ export class EditorPreviewWidget extends EditorWidget { convertToNonPreview(): void { if (this._isPreview) { this._isPreview = false; - this.toDisposeOnLocationChange.dispose(); - this.lastTabbar = undefined; + this.currentTabbar = undefined; this.title.className = this.title.className.replace(PREVIEW_TITLE_CLASS, ''); this.onDidChangePreviewStateEmitter.fire(); this.onDidChangePreviewStateEmitter.dispose(); } } - protected override onAfterAttach(msg: Message): void { - super.onAfterAttach(msg); + protected override handleTabBarChange(oldTabBar?: TabBar | undefined, newTabBar?: TabBar | undefined): void { + super.handleTabBarChange(oldTabBar, newTabBar); if (this._isPreview) { - this.checkForTabbarChange(); - } - } - - protected checkForTabbarChange(): void { - const { parent } = this; - if (parent instanceof DockPanel) { - this.toDisposeOnLocationChange.dispose(); - const newTabbar = find(parent.tabBars(), tabbar => !!tabbar.titles.find(title => title === this.title)); - if (this.lastTabbar && this.lastTabbar !== newTabbar) { - this.convertToNonPreview(); - } else { - this.lastTabbar = newTabbar; - const listener = () => this.checkForTabbarChange(); - parent.layoutModified.connect(listener); - this.toDisposeOnLocationChange.push(Disposable.create(() => parent.layoutModified.disconnect(listener))); - } + if (oldTabBar && newTabBar) { this.convertToNonPreview(); } } } diff --git a/packages/editor/src/browser/editor-widget.ts b/packages/editor/src/browser/editor-widget.ts index 669dff4b97f44..6181e6ec8a610 100644 --- a/packages/editor/src/browser/editor-widget.ts +++ b/packages/editor/src/browser/editor-widget.ts @@ -14,13 +14,17 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 // ***************************************************************************** -import { Disposable, SelectionService, Event, UNTITLED_SCHEME } from '@theia/core/lib/common'; -import { Widget, BaseWidget, Message, Saveable, SaveableSource, Navigatable, StatefulWidget, lock } from '@theia/core/lib/browser'; +import { Disposable, SelectionService, Event, UNTITLED_SCHEME, DisposableCollection } from '@theia/core/lib/common'; +import { Widget, BaseWidget, Message, Saveable, SaveableSource, Navigatable, StatefulWidget, lock, TabBar, DockPanel } from '@theia/core/lib/browser'; import URI from '@theia/core/lib/common/uri'; +import { find } from '@theia/core/shared/@phosphor/algorithm'; import { TextEditor } from './editor'; export class EditorWidget extends BaseWidget implements SaveableSource, Navigatable, StatefulWidget { + protected toDisposeOnTabbarChange = new DisposableCollection(); + protected currentTabbar: TabBar | undefined; + constructor( readonly editor: TextEditor, protected readonly selectionService: SelectionService @@ -31,6 +35,7 @@ export class EditorWidget extends BaseWidget implements SaveableSource, Navigata lock(this.title); } this.toDispose.push(this.editor); + this.toDispose.push(this.toDisposeOnTabbarChange); this.toDispose.push(this.editor.onSelectionChanged(() => this.setSelection())); this.toDispose.push(this.editor.onFocusChanged(() => this.setSelection())); this.toDispose.push(Disposable.create(() => { @@ -68,6 +73,33 @@ export class EditorWidget extends BaseWidget implements SaveableSource, Navigata if (this.isVisible) { this.editor.refresh(); } + this.checkForTabbarChange(); + } + + protected checkForTabbarChange(): void { + const { parent } = this; + if (parent instanceof DockPanel) { + const newTabbar = find(parent.tabBars(), tabbar => !!tabbar.titles.find(title => title === this.title)); + if (this.currentTabbar !== newTabbar) { + this.toDisposeOnTabbarChange.dispose(); + const listener = () => this.checkForTabbarChange(); + parent.layoutModified.connect(listener); + this.toDisposeOnTabbarChange.push(Disposable.create(() => parent.layoutModified.disconnect(listener))); + const last = this.currentTabbar; + this.currentTabbar = newTabbar; + this.handleTabBarChange(last, newTabbar); + } + } + } + + protected handleTabBarChange(oldTabBar?: TabBar, newTabBar?: TabBar): void { + const ownSaveable = Saveable.get(this); + const competingEditors = ownSaveable && newTabBar?.titles.filter(title => title !== this.title + && (title.owner instanceof EditorWidget) + && title.owner.editor.uri.isEqual(this.editor.uri) + && Saveable.get(title.owner) === ownSaveable + ); + competingEditors?.forEach(title => title.owner.close()); } protected override onAfterShow(msg: Message): void {