Skip to content

Commit

Permalink
[#7268] Adjust behavior of all close tab commands so that they respec…
Browse files Browse the repository at this point in the history
…t the widget.title.closable propertySigned-off-by: Vivien Jovet <vivien.jovet@gmail.com>
  • Loading branch information
Hanksha authored and Vivien Jovet committed Mar 6, 2020
1 parent 3d5e4f9 commit 1f82b50
Show file tree
Hide file tree
Showing 6 changed files with 137 additions and 28 deletions.
12 changes: 4 additions & 8 deletions examples/api-samples/src/browser/api-samples-frontend-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,14 +15,10 @@
********************************************************************************/

import { ContainerModule } from 'inversify';
import { CommandContribution } from '@theia/core';
import { LabelProviderContribution } from '@theia/core/lib/browser/label-provider';
import { ApiSamplesContribution } from './api-samples-contribution';
import { SampleDynamicLabelProviderContribution } from './sample-dynamic-label-provider-contribution';
import { bindDynamicLabelProvider } from './label/sample-dymanic-label-provider-command-contribution';
import { bindSampleUnclosableView } from './view/sample-uncloable-view-contribution';

export default new ContainerModule(bind => {
bind(CommandContribution).to(ApiSamplesContribution).inSingletonScope();

bind(SampleDynamicLabelProviderContribution).toSelf().inSingletonScope();
bind(LabelProviderContribution).toService(SampleDynamicLabelProviderContribution);
bindDynamicLabelProvider(bind);
bindSampleUnclosableView(bind);
});
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable, inject } from 'inversify';
import { injectable, inject, interfaces } from 'inversify';
import { Command, CommandContribution, CommandRegistry, CommandHandler } from '@theia/core';
import { FrontendApplicationContribution } from '@theia/core/lib/browser';
import { FrontendApplicationContribution, LabelProviderContribution } from '@theia/core/lib/browser';
import { SampleDynamicLabelProviderContribution } from './sample-dynamic-label-provider-contribution';

export namespace ExampleLabelProviderCommands {
Expand All @@ -29,7 +29,7 @@ export namespace ExampleLabelProviderCommands {
}

@injectable()
export class ApiSamplesContribution implements FrontendApplicationContribution, CommandContribution {
export class SampleDynamicLabelProviderCommandContribution implements FrontendApplicationContribution, CommandContribution {

@inject(SampleDynamicLabelProviderContribution)
protected readonly labelProviderContribution: SampleDynamicLabelProviderContribution;
Expand All @@ -53,3 +53,10 @@ export class ExampleLabelProviderCommandHandler implements CommandHandler {
}

}

export const bindDynamicLabelProvider = (bind: interfaces.Bind) => {
bind(SampleDynamicLabelProviderContribution).toSelf().inSingletonScope();
bind(LabelProviderContribution).toService(SampleDynamicLabelProviderContribution);
bind(CommandContribution).to(SampleDynamicLabelProviderCommandContribution).inSingletonScope();
};

Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,9 @@
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { injectable } from 'inversify';
import { DefaultUriLabelProviderContribution, DidChangeLabelEvent } from '@theia/core/lib/browser/label-provider';
import URI from '@theia/core/lib/common/uri';
import { injectable } from 'inversify';
import { Emitter, Event } from '@theia/core';

@injectable()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
/********************************************************************************
* Copyright (C) 2020 TORO Limited and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { AbstractViewContribution, bindViewContribution, WidgetFactory } from '@theia/core/lib/browser';
import { SampleViewUnclosableView } from './sample-unclosable-view';
import { injectable, interfaces } from 'inversify';

@injectable()
export class SampleUnclosableViewContribution extends AbstractViewContribution<SampleViewUnclosableView> {

static readonly SAMPLE_UNCLOSABLE_VIEW_TOGGLE_COMMAND_ID = 'sampleUnclosableView:toggle';

constructor() {
super({
widgetId: SampleViewUnclosableView.ID,
widgetName: 'Sample Unclosable View',
toggleCommandId: SampleUnclosableViewContribution.SAMPLE_UNCLOSABLE_VIEW_TOGGLE_COMMAND_ID,
defaultWidgetOptions: {
area: 'main'
}
});
}
}

export const bindSampleUnclosableView = (bind: interfaces.Bind) => {
bindViewContribution(bind, SampleUnclosableViewContribution);
bind(SampleViewUnclosableView).toSelf();
bind(WidgetFactory).toDynamicValue(ctx => ({
id: SampleViewUnclosableView.ID,
createWidget: () => ctx.container.get<SampleViewUnclosableView>(SampleViewUnclosableView)
}));
};
46 changes: 46 additions & 0 deletions examples/api-samples/src/browser/view/sample-unclosable-view.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
/********************************************************************************
* Copyright (C) 2020 TORO Limited and others.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the Eclipse
* Public License v. 2.0 are satisfied: GNU General Public License, version 2
* with the GNU Classpath Exception which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
********************************************************************************/

import { ReactWidget } from '@theia/core/lib/browser';
import { injectable, postConstruct } from 'inversify';
import * as React from 'react';

/**
* This sample view is used to demo the behavior of "Widget.title.closable".
*/
@injectable()
export class SampleViewUnclosableView extends ReactWidget {
static readonly ID = 'sampleView';

@postConstruct()
init(): void {
this.id = SampleViewUnclosableView.ID;
this.title.caption = 'Sample';
this.title.label = 'Sample';
this.title.iconClass = 'fa fa-window-maximize';
this.title.closable = true;
this.update();
}

protected render(): React.ReactNode {
return (
<div>
Closable
<input type="checkbox" defaultChecked={this.title.closable} onChange={e => this.title.closable = e.target.checked} />
</div>
);
}
}
47 changes: 31 additions & 16 deletions packages/core/src/browser/common-frontend-contribution.ts
Original file line number Diff line number Diff line change
Expand Up @@ -520,7 +520,14 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
execute: () => this.shell.activatePreviousTab()
});
commandRegistry.registerCommand(CommonCommands.CLOSE_TAB, {
isEnabled: (event?: Event) => this.findTabBar(event) !== undefined,
isEnabled: (event?: Event) => {
const tabBar = this.findTabBar(event);
if (!tabBar) {
return false;
}
const currentTitle = this.findTitle(tabBar, event);
return currentTitle !== undefined && currentTitle.closable;
},
execute: (event?: Event) => {
const tabBar = this.findTabBar(event)!;
const currentTitle = this.findTitle(tabBar, event);
Expand All @@ -530,19 +537,22 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
commandRegistry.registerCommand(CommonCommands.CLOSE_OTHER_TABS, {
isEnabled: (event?: Event) => {
const tabBar = this.findTabBar(event);
return tabBar !== undefined && tabBar.titles.length > 1;
if (!tabBar) {
return false;
}
const currentTitle = this.findTitle(tabBar, event);
return tabBar.titles.some(title => title !== currentTitle && title.closable);
},
execute: (event?: Event) => {
const tabBar = this.findTabBar(event)!;
const currentTitle = this.findTitle(tabBar, event);
const area = this.shell.getAreaFor(tabBar)!;
this.shell.closeTabs(area, title => title !== currentTitle);
this.shell.closeTabs(tabBar, title => title !== currentTitle && title.closable);
}
});
commandRegistry.registerCommand(CommonCommands.CLOSE_RIGHT_TABS, {
isEnabled: (event?: Event) => {
const tabBar = this.findTabBar(event);
return tabBar !== undefined && tabBar.currentIndex < tabBar.titles.length - 1;
return tabBar !== undefined && tabBar.titles.some((title, index) => index > tabBar.currentIndex && title.closable);
},
isVisible: (event?: Event) => {
const area = this.findTabArea(event);
Expand All @@ -551,32 +561,37 @@ export class CommonFrontendContribution implements FrontendApplicationContributi
execute: (event?: Event) => {
const tabBar = this.findTabBar(event)!;
const currentIndex = tabBar.currentIndex;
this.shell.closeTabs(tabBar, (_, index) => index > currentIndex);
this.shell.closeTabs(tabBar, (title, index) => index > currentIndex && title.closable);
}
});
commandRegistry.registerCommand(CommonCommands.CLOSE_ALL_TABS, {
isEnabled: (event?: Event) => this.findTabBar(event) !== undefined,
execute: (event?: Event) => this.shell.closeTabs(this.findTabArea(event)!)
isEnabled: (event?: Event) => {
const tabBar = this.findTabBar(event);
return tabBar !== undefined && tabBar.titles.some(title => title.closable);
},
execute: (event?: Event) => this.shell.closeTabs(this.findTabBar(event)!, title => title.closable)
});
commandRegistry.registerCommand(CommonCommands.CLOSE_MAIN_TAB, {
isEnabled: () => this.shell.getCurrentWidget('main') !== undefined,
isEnabled: () => {
const currentWidget = this.shell.getCurrentWidget('main');
return currentWidget !== undefined && currentWidget.title.closable;
},
execute: () => this.shell.getCurrentWidget('main')!.close()
});
commandRegistry.registerCommand(CommonCommands.CLOSE_OTHER_MAIN_TABS, {
isEnabled: () => {
const tabBars = this.shell.mainAreaTabBars;
return tabBars.length > 1 || tabBars.length === 1 && tabBars[0].titles.length > 1;
const currentWidget = this.shell.getCurrentWidget('main');
return currentWidget !== undefined &&
this.shell.mainAreaTabBars.some(tb => tb.titles.some(title => title.owner !== currentWidget && title.closable));
},
execute: () => {
const currentWidget = this.shell.getCurrentWidget('main');
if (currentWidget !== undefined) {
this.shell.closeTabs('main', title => title.owner !== currentWidget);
}
this.shell.closeTabs('main', title => title.owner !== currentWidget && title.closable);
}
});
commandRegistry.registerCommand(CommonCommands.CLOSE_ALL_MAIN_TABS, {
isEnabled: () => this.shell.mainAreaTabBars.find(tb => tb.titles.length > 0) !== undefined,
execute: () => this.shell.closeTabs('main')
isEnabled: () => this.shell.mainAreaTabBars.some(tb => tb.titles.some(title => title.closable)),
execute: () => this.shell.closeTabs('main', title => title.closable)
});
commandRegistry.registerCommand(CommonCommands.COLLAPSE_PANEL, {
isEnabled: (event?: Event) => ApplicationShell.isSideArea(this.findTabArea(event)),
Expand Down

0 comments on commit 1f82b50

Please sign in to comment.