Skip to content

Commit 35f25a9

Browse files
author
Anas Shahid
committed
[explorer]: Badge count for dirty editors
Fixes: #8296 Adds a badge count for dirty editors on the explorer tab icon. Signed-off-by: Anas Shahid <[email protected]>
1 parent fe24630 commit 35f25a9

File tree

2 files changed

+75
-0
lines changed

2 files changed

+75
-0
lines changed

packages/navigator/src/browser/navigator-frontend-module.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ import { NavigatorContextKeyService } from './navigator-context-key-service';
3333
import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar';
3434
import { NavigatorDiff } from './navigator-diff';
3535
import { NavigatorLayoutVersion3Migration } from './navigator-layout-migrations';
36+
import { NavigatorTabBarDecorator } from './navigator-tab-bar-decorator';
37+
import { TabBarDecorator } from '@theia/core/lib/browser/shell/tab-bar-decorator';
3638

3739
export default new ContainerModule(bind => {
3840
bindFileNavigatorPreferences(bind);
@@ -72,4 +74,7 @@ export default new ContainerModule(bind => {
7274
bind(ApplicationShellLayoutMigration).to(NavigatorLayoutVersion3Migration).inSingletonScope();
7375

7476
bind(NavigatorDiff).toSelf().inSingletonScope();
77+
bind(NavigatorTabBarDecorator).toSelf().inSingletonScope();
78+
bind(FrontendApplicationContribution).toService(NavigatorTabBarDecorator);
79+
bind(TabBarDecorator).toService(NavigatorTabBarDecorator);
7580
});
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
/********************************************************************************
2+
* Copyright (C) 2020 Ericsson and others.
3+
*
4+
* This program and the accompanying materials are made available under the
5+
* terms of the Eclipse Public License v. 2.0 which is available at
6+
* http://www.eclipse.org/legal/epl-2.0.
7+
*
8+
* This Source Code may also be made available under the following Secondary
9+
* Licenses when the conditions for such availability set forth in the Eclipse
10+
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
11+
* with the GNU Classpath Exception which is available at
12+
* https://www.gnu.org/software/classpath/license.html.
13+
*
14+
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
15+
********************************************************************************/
16+
17+
import { injectable } from 'inversify';
18+
import { Emitter, Event } from '@theia/core/lib/common/event';
19+
import { TabBarDecorator } from '@theia/core/lib/browser/shell/tab-bar-decorator';
20+
import { EXPLORER_VIEW_CONTAINER_ID } from './navigator-widget';
21+
import { ApplicationShell, FrontendApplication, FrontendApplicationContribution, Saveable, Title, Widget } from '@theia/core/lib/browser';
22+
import { WidgetDecoration } from '@theia/core/lib/browser/widget-decoration';
23+
import { Disposable, DisposableCollection } from '@theia/core/lib/common/disposable';
24+
25+
@injectable()
26+
export class NavigatorTabBarDecorator implements TabBarDecorator, FrontendApplicationContribution {
27+
readonly id = 'theia-navigator-tabbar-decorator';
28+
protected applicationShell: ApplicationShell;
29+
30+
protected readonly emitter = new Emitter<void>();
31+
private readonly toDispose = new DisposableCollection();
32+
private readonly toDisposeOnDirtyChanged = new Map<string, Disposable>();
33+
34+
onStart(app: FrontendApplication): void {
35+
this.applicationShell = app.shell;
36+
if (!!this.getDirtyEditorsCount()) {
37+
this.fireDidChangeDecorations();
38+
}
39+
this.toDispose.pushAll([
40+
this.applicationShell.onDidAddWidget(widget => {
41+
const saveable = Saveable.get(widget);
42+
if (saveable) {
43+
this.toDisposeOnDirtyChanged.set(widget.id, saveable.onDirtyChanged(() => this.fireDidChangeDecorations()));
44+
}
45+
}),
46+
this.applicationShell.onDidRemoveWidget(widget => this.toDisposeOnDirtyChanged.get(widget.id)?.dispose())
47+
]);
48+
}
49+
50+
decorate(title: Title<Widget>): WidgetDecoration.Data[] {
51+
if (title.owner.id === EXPLORER_VIEW_CONTAINER_ID) {
52+
const changes = this.getDirtyEditorsCount();
53+
return changes > 0 ? [{ badge: changes }] : [];
54+
} else {
55+
return [];
56+
}
57+
}
58+
59+
protected getDirtyEditorsCount(): number {
60+
return this.applicationShell.widgets.filter(widget => Saveable.isDirty(widget)).length;
61+
}
62+
63+
get onDidChangeDecorations(): Event<void> {
64+
return this.emitter.event;
65+
}
66+
67+
protected fireDidChangeDecorations(): void {
68+
this.emitter.fire(undefined);
69+
}
70+
}

0 commit comments

Comments
 (0)