dialogService.ts 4.9 KB
Newer Older
1 2 3 4 5 6 7
/*---------------------------------------------------------------------------------------------
 *  Copyright (c) Microsoft Corporation. All rights reserved.
 *  Licensed under the MIT License. See License.txt in the project root for license information.
 *--------------------------------------------------------------------------------------------*/

'use strict';

8
import * as nls from 'vs/nls';
9 10
import product from 'vs/platform/node/product';
import { TPromise } from 'vs/base/common/winjs.base';
11
import Severity from 'vs/base/common/severity';
12
import { isLinux, isWindows } from 'vs/base/common/platform';
13 14
import { IWindowService } from 'vs/platform/windows/common/windows';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
15
import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions } from 'vs/platform/dialogs/common/dialogs';
J
Joao Moreno 已提交
16
import { ILogService } from 'vs/platform/log/common/log';
17

18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
interface IMassagedMessageBoxOptions {

	/**
	 * OS massaged message box options.
	 */
	options: Electron.MessageBoxOptions;

	/**
	 * Since the massaged result of the message box options potentially
	 * changes the order of buttons, we have to keep a map of these
	 * changes so that we can still return the correct index to the caller.
	 */
	buttonIndexMap: number[];
}

33
export class DialogService implements IDialogService {
34

B
Benjamin Pasero 已提交
35
	_serviceBrand: any;
36 37

	constructor(
J
Joao Moreno 已提交
38 39
		@IWindowService private windowService: IWindowService,
		@ILogService private logService: ILogService
B
Benjamin Pasero 已提交
40
	) { }
41

B
Benjamin Pasero 已提交
42
	confirm(confirmation: IConfirmation): TPromise<IConfirmationResult> {
J
Joao Moreno 已提交
43 44
		this.logService.trace('DialogService#confirm', confirmation.message);

45
		const { options, buttonIndexMap } = this.massageMessageBoxOptions(this.getConfirmOptions(confirmation));
46

47
		return this.windowService.showMessageBox(options).then(result => {
48
			return {
49
				confirmed: buttonIndexMap[result.button] === 0 ? true : false,
50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
				checkboxChecked: result.checkboxChecked
			} as IConfirmationResult;
		});
	}

	private getConfirmOptions(confirmation: IConfirmation): Electron.MessageBoxOptions {
		const buttons: string[] = [];
		if (confirmation.primaryButton) {
			buttons.push(confirmation.primaryButton);
		} else {
			buttons.push(nls.localize({ key: 'yesButton', comment: ['&& denotes a mnemonic'] }, "&&Yes"));
		}

		if (confirmation.secondaryButton) {
			buttons.push(confirmation.secondaryButton);
		} else if (typeof confirmation.secondaryButton === 'undefined') {
			buttons.push(nls.localize('cancelButton', "Cancel"));
		}

		const opts: Electron.MessageBoxOptions = {
			title: confirmation.title,
			message: confirmation.message,
			buttons,
			cancelId: 1
		};

		if (confirmation.detail) {
			opts.detail = confirmation.detail;
		}

		if (confirmation.type) {
			opts.type = confirmation.type;
		}

		if (confirmation.checkbox) {
			opts.checkboxLabel = confirmation.checkbox.label;
			opts.checkboxChecked = confirmation.checkbox.checked;
		}

		return opts;
	}

B
Benjamin Pasero 已提交
92
	show(severity: Severity, message: string, buttons: string[], dialogOptions?: IDialogOptions): TPromise<number> {
J
Joao Moreno 已提交
93 94
		this.logService.trace('DialogService#show', message);

95 96 97
		const { options, buttonIndexMap } = this.massageMessageBoxOptions({
			message,
			buttons,
98
			type: (severity === Severity.Info) ? 'question' : (severity === Severity.Error) ? 'error' : (severity === Severity.Warning) ? 'warning' : 'none',
99 100 101
			cancelId: dialogOptions ? dialogOptions.cancelId : void 0,
			detail: dialogOptions ? dialogOptions.detail : void 0
		});
102 103

		return this.windowService.showMessageBox(options).then(result => buttonIndexMap[result.button]);
104 105
	}

106 107
	private massageMessageBoxOptions(options: Electron.MessageBoxOptions): IMassagedMessageBoxOptions {
		let buttonIndexMap = options.buttons.map((button, index) => index);
108 109
		let buttons = options.buttons.map(button => mnemonicButtonLabel(button));
		let cancelId = options.cancelId;
110

111 112 113
		// Linux: order of buttons is reverse
		// macOS: also reverse, but the OS handles this for us!
		if (isLinux) {
114
			buttons = buttons.reverse();
115 116
			buttonIndexMap = buttonIndexMap.reverse();
		}
117

118 119
		// Default Button (always first one)
		options.defaultId = buttonIndexMap[0];
120

121
		// Cancel Button
122
		if (typeof cancelId === 'number') {
123

124 125 126 127
			// Ensure the cancelId is the correct one from our mapping
			cancelId = buttonIndexMap[cancelId];

			// macOS/Linux: the cancel button should always be to the left of the primary action
128
			// if we see more than 2 buttons, move the cancel one to the left of the primary
129 130 131 132
			if (!isWindows && buttons.length > 2 && cancelId !== 1) {
				const cancelButton = buttons[cancelId];
				buttons.splice(cancelId, 1);
				buttons.splice(1, 0, cancelButton);
133

134 135
				const cancelButtonIndex = buttonIndexMap[cancelId];
				buttonIndexMap.splice(cancelId, 1);
136 137
				buttonIndexMap.splice(1, 0, cancelButtonIndex);

138 139
				cancelId = 1;
			}
140 141
		}

142 143
		options.buttons = buttons;
		options.cancelId = cancelId;
144 145
		options.noLink = true;
		options.title = options.title || product.nameLong;
146

147
		return { options, buttonIndexMap };
148 149
	}
}