From 1ca29cf435ed61c3defe917b05a0349c77beda87 Mon Sep 17 00:00:00 2001 From: Roman Shevchenko Date: Fri, 11 Feb 2022 10:18:39 +0100 Subject: [PATCH] [ui] NIO-based file chooser: preserving selection on reloads; focusing created files GitOrigin-RevId: 2313d93dcea1449c35b70cef9bc1cdbe1dc0f3bb --- .../openapi/fileChooser/FileChooserPanel.java | 3 +- .../fileChooser/actions/FileDeleteAction.java | 2 +- .../fileChooser/actions/NewFileAction.java | 6 ++-- .../fileChooser/actions/NewFolderAction.java | 6 ++-- .../actions/RefreshFileChooserAction.java | 4 +-- .../impl/FileChooserPanelImpl.java | 30 +++++++++++-------- .../impl/NewFileChooserDialogImpl.java | 2 +- 7 files changed, 30 insertions(+), 23 deletions(-) diff --git a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserPanel.java b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserPanel.java index e412eb213fe5..f6fdfa196a7f 100644 --- a/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserPanel.java +++ b/platform/platform-api/src/com/intellij/openapi/fileChooser/FileChooserPanel.java @@ -23,7 +23,8 @@ public interface FileChooserPanel { @NotNull JComponent getComponent(); void load(@Nullable Path path); - void reload(); + + void reload(@Nullable Path focusOn); boolean showPathBar(); void showPathBar(boolean show); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/FileDeleteAction.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/FileDeleteAction.java index 88696d729c9e..b07102f62a07 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/FileDeleteAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/FileDeleteAction.java @@ -57,7 +57,7 @@ public class FileDeleteAction extends FileChooserAction { return null; } }); - panel.reload(); + panel.reload(null); } catch (IOException ex) { Messages.showErrorDialog(panel.getComponent(), IoErrorText.message(ex), CommonBundle.getErrorTitle()); diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/NewFileAction.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/NewFileAction.java index 3c43f1b85f00..a5c9a4c0a89a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/NewFileAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/NewFileAction.java @@ -55,14 +55,14 @@ public class NewFileAction extends FileChooserAction implements LightEditCompati while (true) { var input = MessagesService.getInstance().showInputDialog(null, panel.getComponent(), prompt, title, null, initial, validator, selection, null); - if (input == null) return; + if (input == null) break; var name = input.trim(); initial = name; selection = null; var progress = UIBundle.message("file.chooser.creating.progress", name); try { - ProgressManager.getInstance().run(new Task.WithResult(e.getProject(), panel.getComponent(), progress, true) { + var newFile = ProgressManager.getInstance().run(new Task.WithResult(e.getProject(), panel.getComponent(), progress, true) { @Override protected Path compute(@NotNull ProgressIndicator indicator) throws IOException { indicator.setIndeterminate(true); @@ -73,7 +73,7 @@ public class NewFileAction extends FileChooserAction implements LightEditCompati return newFile; } }); - panel.reload(); + panel.reload(newFile); break; } catch (IOException | InvalidPathException ex) { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/NewFolderAction.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/NewFolderAction.java index 8422ea27fc72..1aa8bf7dd74a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/NewFolderAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/NewFolderAction.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.fileChooser.actions; import com.intellij.CommonBundle; @@ -68,7 +68,7 @@ public class NewFolderAction extends FileChooserAction implements LightEditCompa try { var progress = UIBundle.message("file.chooser.creating.progress", name); - ProgressManager.getInstance().run(new Task.WithResult(e.getProject(), panel.getComponent(), progress, true) { + var newDir = ProgressManager.getInstance().run(new Task.WithResult(e.getProject(), panel.getComponent(), progress, true) { @Override protected Path compute(@NotNull ProgressIndicator indicator) throws IOException { indicator.setIndeterminate(true); @@ -78,7 +78,7 @@ public class NewFolderAction extends FileChooserAction implements LightEditCompa return newDirectory; } }); - panel.reload(); + panel.reload(newDir); break; } catch (IOException | InvalidPathException ex) { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/RefreshFileChooserAction.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/RefreshFileChooserAction.java index 35baf7fdd753..0ae605ca923d 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/RefreshFileChooserAction.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/actions/RefreshFileChooserAction.java @@ -1,4 +1,4 @@ -// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. +// Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.intellij.openapi.fileChooser.actions; import com.intellij.ide.lightEdit.LightEditCompatible; @@ -16,7 +16,7 @@ public class RefreshFileChooserAction extends FileChooserAction implements Light @Override protected void actionPerformed(@NotNull FileChooserPanel panel, @NotNull AnActionEvent e) { - panel.reload(); + panel.reload(null); } @Override diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/impl/FileChooserPanelImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/impl/FileChooserPanelImpl.java index 269fab1a552d..d0d756310d0a 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/impl/FileChooserPanelImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/impl/FileChooserPanelImpl.java @@ -174,7 +174,7 @@ final class FileChooserPanelImpl extends JBPanel implement UIUtil.invokeLaterIfNeeded(() -> { synchronized (myLock) { if (key == myWatchKey && myCurrentDirectory != null) { - doLoad(myCurrentDirectory); + reload(null); } } }); @@ -197,10 +197,10 @@ final class FileChooserPanelImpl extends JBPanel implement private void openItemAtIndex(int idx, InputEvent e) { FsItem item = myModel.get(idx); if (item.directory) { - doLoad(item.path, item.name == FsItem.UPLINK ? UPPER_LEVEL : 0); + load(item.path, null, item.name == FsItem.UPLINK ? UPPER_LEVEL : 0); } else if (myDescriptor.isChooseJarContents() && myRegistry.getFileTypeByFileName(item.name) == ArchiveFileType.INSTANCE) { - doLoad(item.path, INTO_ARCHIVE); + load(item.path, null, INTO_ARCHIVE); } else { myCallback.run(); @@ -246,7 +246,7 @@ final class FileChooserPanelImpl extends JBPanel implement @Override public void load(@Nullable Path path) { if (path == null || path.isAbsolute()) { - doLoad(path); + load(path, null, 0); } else { throw new IllegalArgumentException("Not absolute: " + path); @@ -254,9 +254,15 @@ final class FileChooserPanelImpl extends JBPanel implement } @Override - public void reload() { + public void reload(@Nullable Path focusOn) { + if (focusOn == null) { + FsItem value = myList.getSelectedValue(); + if (value != null) { + focusOn = value.path; + } + } synchronized (myLock) { - doLoad(myCurrentDirectory); + load(myCurrentDirectory, focusOn, 0); } } @@ -283,11 +289,13 @@ final class FileChooserPanelImpl extends JBPanel implement myShowHiddenFiles = show; synchronized (myLock) { if (myCurrentDirectory != null) { + var selection = myList.getSelectedValue(); myModel.clear(); for (int i = 1; i < myCurrentContent.size(); i++) { // excluding `.` FsItem item = myCurrentContent.get(i); if (show || item.visible) myModel.add(item); } + myList.setSelectedValue(selection, true); } } } @@ -330,14 +338,10 @@ final class FileChooserPanelImpl extends JBPanel implement }); } - private void doLoad(@Nullable Path path) { - doLoad(path, 0); - } - private static final int UPPER_LEVEL = 1; private static final int INTO_ARCHIVE = 2; - private void doLoad(@Nullable Path path, int direction) { + private void load(@Nullable Path path, @Nullable Path focusOn, int direction) { synchronized (myLock) { myPath.setItem(path != null ? new PathWrapper(path) : null); myModel.clear(); @@ -354,7 +358,9 @@ final class FileChooserPanelImpl extends JBPanel implement myCurrentTask = pair(id, ProcessIOExecutorService.INSTANCE.submit(() -> { var directory = directoryToLoad(path, direction == INTO_ARCHIVE); if (directory != null) { - var pathToSelect = childDir != null && childDir.getParent() == null && isJar(childDir.toUri()) ? parent(childDir) : childDir; + var pathToSelect = focusOn != null ? focusOn : + childDir != null && childDir.getParent() == null && isJar(childDir.toUri()) ? parent(childDir) : + childDir; loadDirectory(directory, pathToSelect, id); } else { diff --git a/platform/platform-impl/src/com/intellij/openapi/fileChooser/impl/NewFileChooserDialogImpl.java b/platform/platform-impl/src/com/intellij/openapi/fileChooser/impl/NewFileChooserDialogImpl.java index 91509aab7598..00736b49d04f 100644 --- a/platform/platform-impl/src/com/intellij/openapi/fileChooser/impl/NewFileChooserDialogImpl.java +++ b/platform/platform-impl/src/com/intellij/openapi/fileChooser/impl/NewFileChooserDialogImpl.java @@ -134,7 +134,7 @@ final class NewFileChooserDialogImpl extends DialogWrapper implements FileChoose var urls = misses.stream().map(s -> "   " + s).collect(Collectors.joining("
")); var message = UIBundle.message("file.chooser.vfs.lookup", urls); Messages.showErrorDialog(myPanel, message, getTitle()); - myPanel.reload(); + myPanel.reload(null); return; }