未验证 提交 60fe7184 编写于 作者: M Martin Aeschlimann 提交者: GitHub

Merge pull request #68419 from Microsoft/aeschli/dialog-service

DialogService: open remote based on defaultURI and current window
......@@ -66,6 +66,12 @@ export interface ISaveDialogOptions {
* A human-readable string for the ok button
*/
saveLabel?: string;
/**
* Specifies a list of schemas for the file systems the user can save to. If not specified, uses the schema of the defaultURI or, if also not specified,
* the schema of the current window.
*/
availableFileSystems?: string[];
}
export interface IOpenDialogOptions {
......@@ -104,6 +110,12 @@ export interface IOpenDialogOptions {
* like "TypeScript", and an array of extensions.
*/
filters?: FileFilter[];
/**
* Specifies a list of schemas for the file systems the user can load from. If not specified, uses the schema of the defaultURI or, if also not available,
* the schema of the current window.
*/
availableFileSystems?: string[];
}
......@@ -150,21 +162,21 @@ export interface IFileDialogService {
/**
* The default path for a new file based on previously used files.
* @param schemeFilter The scheme of the file path.
* @param schemeFilter The scheme of the file path. If no filter given, the scheme of the current window is used.
*/
defaultFilePath(schemeFilter: string): URI | undefined;
defaultFilePath(schemeFilter?: string): URI | undefined;
/**
* The default path for a new folder based on previously used folders.
* @param schemeFilter The scheme of the folder path.
* @param schemeFilter The scheme of the folder path. If no filter given, the scheme of the current window is used.
*/
defaultFolderPath(schemeFilter: string): URI | undefined;
defaultFolderPath(schemeFilter?: string): URI | undefined;
/**
* The default path for a new workspace based on previously used workspaces.
* @param schemeFilter The scheme of the workspace path.
* @param schemeFilter The scheme of the workspace path. If no filter given, the scheme of the current window is used.
*/
defaultWorkspacePath(schemeFilter: string): URI | undefined;
defaultWorkspacePath(schemeFilter?: string): URI | undefined;
/**
* Shows a file-folder selection dialog and opens the selected entry.
......
......@@ -15,7 +15,6 @@ import { IEditorService } from 'vs/workbench/services/editor/common/editorServic
import { ICommandService } from 'vs/platform/commands/common/commands';
import { ADD_ROOT_FOLDER_COMMAND_ID, ADD_ROOT_FOLDER_LABEL, PICK_WORKSPACE_FOLDER_COMMAND_ID } from 'vs/workbench/browser/actions/workspaceCommands';
import { URI } from 'vs/base/common/uri';
import { Schemas } from 'vs/base/common/network';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { INotificationService } from 'vs/platform/notification/common/notification';
......@@ -161,7 +160,7 @@ export class SaveWorkspaceAsAction extends Action {
saveLabel: mnemonicButtonLabel(nls.localize({ key: 'save', comment: ['&& denotes a mnemonic'] }, "&&Save")),
title: nls.localize('saveWorkspace', "Save Workspace"),
filters: WORKSPACE_FILTER,
defaultUri: this.dialogService.defaultWorkspacePath(Schemas.file)
defaultUri: this.dialogService.defaultWorkspacePath()
});
}
}
......
......@@ -18,7 +18,6 @@ import { IQuickInputService, IPickOptions, IQuickPickItem } from 'vs/platform/qu
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { Schemas } from 'vs/base/common/network';
import { IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
export const ADD_ROOT_FOLDER_COMMAND_ID = 'addRootFolder';
......@@ -64,7 +63,7 @@ CommandsRegistry.registerCommand({
title: nls.localize('addFolderToWorkspaceTitle', "Add Folder to Workspace"),
canSelectFolders: true,
canSelectMany: true,
defaultUri: dialogsService.defaultFolderPath(Schemas.file)
defaultUri: dialogsService.defaultFolderPath()
}).then((folders): Promise<any> | null => {
if (!folders || !folders.length) {
return null;
......
......@@ -176,7 +176,7 @@ import { ToggleDevToolsAction } from 'vs/workbench/electron-browser/actions/deve
import { registerWindowDriver } from 'vs/platform/driver/electron-browser/driver';
import { IExtensionUrlHandler, ExtensionUrlHandler } from 'vs/workbench/services/extensions/electron-browser/inactiveExtensionUrlHandler';
import { WorkbenchThemeService } from 'vs/workbench/services/themes/electron-browser/workbenchThemeService';
import { RemoteFileDialogService, DialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService';
import { DialogService, FileDialogService } from 'vs/workbench/services/dialogs/electron-browser/dialogService';
import { ShowPreviousWindowTab, MoveWindowTabToNewWindow, MergeAllWindowTabs, ShowNextWindowTab, ToggleWindowTabsBar, NewWindowTab, OpenRecentAction, ReloadWindowAction, ReloadWindowWithExtensionsDisabledAction } from 'vs/workbench/electron-browser/actions/windowActions';
import { IBroadcastService, BroadcastService } from 'vs/workbench/services/broadcast/electron-browser/broadcastService';
import { WindowService } from 'vs/platform/windows/electron-browser/windowService';
......@@ -716,7 +716,7 @@ export class Workbench extends Disposable implements IPartService {
serviceCollection.set(IHistoryService, new SyncDescriptor(HistoryService));
// File Dialogs
serviceCollection.set(IFileDialogService, new SyncDescriptor(RemoteFileDialogService));
serviceCollection.set(IFileDialogService, new SyncDescriptor(FileDialogService));
// Backup File Service
if (this.workbenchParams.configuration.backupPath) {
......
......@@ -7,7 +7,7 @@ import * as nls from 'vs/nls';
import product from 'vs/platform/node/product';
import Severity from 'vs/base/common/severity';
import { isLinux, isWindows } from 'vs/base/common/platform';
import { IWindowService, INativeOpenDialogOptions, OpenDialogOptions } from 'vs/platform/windows/common/windows';
import { IWindowService, INativeOpenDialogOptions, OpenDialogOptions, IURIToOpen, FileFilter } from 'vs/platform/windows/common/windows';
import { mnemonicButtonLabel } from 'vs/base/common/labels';
import { IDialogService, IConfirmation, IConfirmationResult, IDialogOptions, IPickAndOpenOptions, ISaveDialogOptions, IOpenDialogOptions, IFileDialogService } from 'vs/platform/dialogs/common/dialogs';
import { ILogService } from 'vs/platform/log/common/log';
......@@ -15,11 +15,12 @@ import { IWorkspaceContextService, WorkbenchState } from 'vs/platform/workspace/
import { IHistoryService } from 'vs/workbench/services/history/common/history';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { URI } from 'vs/base/common/uri';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { Schemas } from 'vs/base/common/network';
import * as resources from 'vs/base/common/resources';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { RemoteFileDialog } from 'vs/workbench/services/dialogs/electron-browser/remoteFileDialog';
import { WORKSPACE_EXTENSION } from 'vs/platform/workspaces/common/workspaces';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
interface IMassagedMessageBoxOptions {
......@@ -163,10 +164,10 @@ export class FileDialogService implements IFileDialogService {
@IWorkspaceContextService private readonly contextService: IWorkspaceContextService,
@IHistoryService private readonly historyService: IHistoryService,
@IEnvironmentService private readonly environmentService: IEnvironmentService,
@IInstantiationService private readonly instantiationService: IInstantiationService,
@IInstantiationService private readonly instantiationService: IInstantiationService
) { }
defaultFilePath(schemeFilter: string): URI | undefined {
defaultFilePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined {
// Check for last active file first...
let candidate = this.historyService.getLastActiveFile(schemeFilter);
......@@ -179,7 +180,7 @@ export class FileDialogService implements IFileDialogService {
return candidate && resources.dirname(candidate) || undefined;
}
defaultFolderPath(schemeFilter: string): URI | undefined {
defaultFolderPath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined {
// Check for last active file root first...
let candidate = this.historyService.getLastActiveWorkspaceRoot(schemeFilter);
......@@ -192,7 +193,7 @@ export class FileDialogService implements IFileDialogService {
return candidate && resources.dirname(candidate) || undefined;
}
defaultWorkspacePath(schemeFilter: string): URI | undefined {
defaultWorkspacePath(schemeFilter = this.getSchemeFilterForWindow()): URI | undefined {
// Check for current workspace config file first...
if (this.contextService.getWorkbenchState() === WorkbenchState.WORKSPACE) {
......@@ -217,36 +218,66 @@ export class FileDialogService implements IFileDialogService {
}
pickFileFolderAndOpen(options: IPickAndOpenOptions): Promise<any> {
const defaultUri = options.defaultUri;
if (!defaultUri) {
options.defaultUri = this.defaultFilePath(Schemas.file);
const schema = this.getFileSystemSchema(options);
if (!options.defaultUri) {
options.defaultUri = this.defaultFilePath(schema);
}
if (schema !== Schemas.file) {
const title = nls.localize('openFileOrFolder.title', 'Open File Or Folder');
const availableFileSystems = [schema, Schemas.file]; // always allow file as well
return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }, options.forceNewWindow, true);
}
return this.windowService.pickFileFolderAndOpen(this.toNativeOpenDialogOptions(options));
}
pickFileAndOpen(options: IPickAndOpenOptions): Promise<any> {
const defaultUri = options.defaultUri;
if (!defaultUri) {
options.defaultUri = this.defaultFilePath(Schemas.file);
const schema = this.getFileSystemSchema(options);
if (!options.defaultUri) {
options.defaultUri = this.defaultFilePath(schema);
}
if (schema !== Schemas.file) {
const title = nls.localize('openFile.title', 'Open File');
const availableFileSystems = [schema, Schemas.file]; // always allow file as well
return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }, options.forceNewWindow, true);
}
return this.windowService.pickFileAndOpen(this.toNativeOpenDialogOptions(options));
}
pickFolderAndOpen(options: IPickAndOpenOptions): Promise<any> {
const defaultUri = options.defaultUri;
if (!defaultUri) {
options.defaultUri = this.defaultFolderPath(Schemas.file);
const schema = this.getFileSystemSchema(options);
if (!options.defaultUri) {
options.defaultUri = this.defaultFolderPath(schema);
}
if (schema !== Schemas.file) {
const title = nls.localize('openFolder.title', 'Open Folder');
const availableFileSystems = [schema, Schemas.file]; // always allow file as well
return this.pickRemoteResourceAndOpen({ canSelectFiles: false, canSelectFolders: true, canSelectMany: false, defaultUri: options.defaultUri, title, availableFileSystems }, options.forceNewWindow, false);
}
return this.windowService.pickFolderAndOpen(this.toNativeOpenDialogOptions(options));
}
pickWorkspaceAndOpen(options: IPickAndOpenOptions): Promise<void> {
const defaultUri = options.defaultUri;
if (!defaultUri) {
options.defaultUri = this.defaultWorkspacePath(Schemas.file);
const schema = this.getFileSystemSchema(options);
if (!options.defaultUri) {
options.defaultUri = this.defaultWorkspacePath(schema);
}
if (schema !== Schemas.file) {
const title = nls.localize('openWorkspace.title', 'Open Workspace');
const filters: FileFilter[] = [{ name: nls.localize('filterName.workspace', 'Workspace'), extensions: [WORKSPACE_EXTENSION] }];
const availableFileSystems = [schema, Schemas.file]; // always allow file as well
return this.pickRemoteResourceAndOpen({ canSelectFiles: true, canSelectFolders: false, canSelectMany: false, defaultUri: options.defaultUri, title, filters, availableFileSystems }, options.forceNewWindow, false);
}
return this.windowService.pickWorkspaceAndOpen(this.toNativeOpenDialogOptions(options));
......@@ -262,9 +293,9 @@ export class FileDialogService implements IFileDialogService {
}
showSaveDialog(options: ISaveDialogOptions): Promise<URI | undefined> {
const defaultUri = options.defaultUri;
if (defaultUri && defaultUri.scheme !== Schemas.file) {
return Promise.reject(new Error('Not supported - Save-dialogs can only be opened on `file`-uris.'));
const schema = this.getFileSystemSchema(options);
if (schema !== Schemas.file) {
return this.saveRemoteResource(options);
}
return this.windowService.showSaveDialog(this.toNativeSaveDialogOptions(options)).then(result => {
......@@ -276,17 +307,16 @@ export class FileDialogService implements IFileDialogService {
});
}
public showSaveRemoteDialog(options: ISaveDialogOptions): Promise<URI | undefined> {
const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog);
return remoteFileDialog.showSaveDialog(options);
}
showOpenDialog(options: IOpenDialogOptions): Promise<URI[] | undefined> {
const defaultUri = options.defaultUri;
if (defaultUri && defaultUri.scheme !== Schemas.file) {
return Promise.reject(new Error('Not supported - Open-dialogs can only be opened on `file`-uris.'));
const schema = this.getFileSystemSchema(options);
if (schema !== Schemas.file) {
return this.pickRemoteResource(options).then(urisToOpen => {
return urisToOpen && urisToOpen.map(uto => uto.uri);
});
}
const defaultUri = options.defaultUri;
const newOptions: OpenDialogOptions = {
title: options.title,
defaultPath: defaultUri && defaultUri.fsPath,
......@@ -312,31 +342,33 @@ export class FileDialogService implements IFileDialogService {
return this.windowService.showOpenDialog(newOptions).then(result => result ? result.map(URI.file) : undefined);
}
public showOpenRemoteDialog(options: IOpenDialogOptions): Promise<void> {
private pickRemoteResourceAndOpen(options: IOpenDialogOptions, forceNewWindow: boolean, forceOpenWorkspaceAsFile: boolean) {
return this.pickRemoteResource(options).then(urisToOpen => {
if (urisToOpen) {
return this.windowService.openWindow(urisToOpen, { forceNewWindow, forceOpenWorkspaceAsFile });
}
return void 0;
});
}
private pickRemoteResource(options: IOpenDialogOptions): Promise<IURIToOpen[] | undefined> {
const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog);
return remoteFileDialog.showOpenDialog(options);
}
}
export class RemoteFileDialogService extends FileDialogService {
private saveRemoteResource(options: ISaveDialogOptions): Promise<URI | undefined> {
const remoteFileDialog = this.instantiationService.createInstance(RemoteFileDialog);
return remoteFileDialog.showSaveDialog(options);
}
constructor(
@IWindowService windowService: IWindowService,
@IWorkspaceContextService contextService: IWorkspaceContextService,
@IHistoryService historyService: IHistoryService,
@IEnvironmentService environmentService: IEnvironmentService,
@IInstantiationService instantiationService: IInstantiationService,
) {
super(windowService, contextService, historyService, environmentService, instantiationService);
private getSchemeFilterForWindow() {
return !this.windowService.getConfiguration().remoteAuthority ? Schemas.file : REMOTE_HOST_SCHEME;
}
public showSaveDialog(options: ISaveDialogOptions): Promise<URI | undefined> {
const defaultUri = options.defaultUri;
if (defaultUri && defaultUri.scheme === REMOTE_HOST_SCHEME) {
return this.showSaveRemoteDialog(options);
}
return super.showSaveDialog(options);
private getFileSystemSchema(options: { availableFileSystems?: string[], defaultUri?: URI }): string {
return options.availableFileSystems && options.availableFileSystems[0] || options.defaultUri && options.defaultUri.scheme || this.getSchemeFilterForWindow();
}
}
function isUntitledWorkspace(path: URI, environmentService: IEnvironmentService): boolean {
......
......@@ -12,10 +12,9 @@ import { URI } from 'vs/base/common/uri';
import { isWindows } from 'vs/base/common/platform';
import { ISaveDialogOptions, IOpenDialogOptions } from 'vs/platform/dialogs/common/dialogs';
import { REMOTE_HOST_SCHEME } from 'vs/platform/remote/common/remoteHosts';
import { IWindowService } from 'vs/platform/windows/common/windows';
import { IWindowService, IURIToOpen } from 'vs/platform/windows/common/windows';
import { ILabelService } from 'vs/platform/label/common/label';
import { IWorkspaceContextService } from 'vs/platform/workspace/common/workspace';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { INotificationService } from 'vs/platform/notification/common/notification';
interface FileQuickPickItem extends IQuickPickItem {
......@@ -43,40 +42,35 @@ export class RemoteFileDialog {
@IWindowService private readonly windowService: IWindowService,
@ILabelService private readonly labelService: ILabelService,
@IWorkspaceContextService private readonly workspaceContextService: IWorkspaceContextService,
@IEditorService private readonly editorService: IEditorService,
@INotificationService private readonly notificationService: INotificationService,
) {
this.remoteAuthority = this.windowService.getConfiguration().remoteAuthority;
}
public async showOpenDialog(options: IOpenDialogOptions = {}): Promise<void> {
if (!this.remoteAuthority) {
this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'Not connected to a remote.'));
return Promise.resolve();
}
public async showOpenDialog(options: IOpenDialogOptions = {}): Promise<IURIToOpen[] | undefined> {
const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' });
if (!this.remoteFileService.canHandleResource(defaultUri)) {
this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'File system provider for {0} is not available.', defaultUri.toString()));
return Promise.resolve(undefined);
}
const title = nls.localize('remoteFileDialog.openTitle', 'Open File or Folder');
return this.pickResource({ title, defaultUri, canSelectFiles: true, canSelectFolders: true }).then(async fileFolderUri => {
if (fileFolderUri) {
const stat = await this.remoteFileService.resolveFile(fileFolderUri);
if (stat.isDirectory) {
return this.windowService.openWindow([{ uri: fileFolderUri, typeHint: 'folder' }]);
} else {
return this.editorService.openEditor({ resource: fileFolderUri }).then(() => {
return Promise.resolve();
});
}
return [{ uri: fileFolderUri, type: stat.isDirectory ? 'folder' : 'file' }];
}
return Promise.resolve();
return Promise.resolve(undefined);
});
}
public showSaveDialog(options: ISaveDialogOptions): Promise<URI | undefined> {
if (!this.remoteAuthority) {
this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'Not connected to a remote.'));
const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' });
if (!this.remoteFileService.canHandleResource(defaultUri)) {
this.notificationService.info(nls.localize('remoteFileDialog.notConnectedToRemote', 'File system provider for {0} is not available.', defaultUri.toString()));
return Promise.resolve(undefined);
}
const defaultUri = options.defaultUri ? options.defaultUri : URI.from({ scheme: REMOTE_HOST_SCHEME, authority: this.remoteAuthority, path: '/' });
return new Promise<URI | undefined>((resolve) => {
let saveNameBox = this.quickInputService.createInputBox();
saveNameBox.title = options.title;
......
......@@ -412,13 +412,13 @@ export class TestFileDialogService implements IFileDialogService {
public _serviceBrand: any;
public defaultFilePath(_schemeFilter: string): URI | undefined {
public defaultFilePath(_schemeFilter?: string): URI | undefined {
return undefined;
}
public defaultFolderPath(_schemeFilter: string): URI | undefined {
public defaultFolderPath(_schemeFilter?: string): URI | undefined {
return undefined;
}
public defaultWorkspacePath(_schemeFilter: string): URI | undefined {
public defaultWorkspacePath(_schemeFilter?: string): URI | undefined {
return undefined;
}
public pickFileFolderAndOpen(_options: IPickAndOpenOptions): Promise<any> {
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册