From fb95e96d57867af14e009fd615f8d1dc06b2f0d1 Mon Sep 17 00:00:00 2001 From: Kirill Kirichenko Date: Wed, 10 Apr 2019 15:12:03 +0300 Subject: [PATCH] IDEA-202744 Implement browse button inside combo boxes. --- .../execution/ui/JreComboboxEditor.java | 37 +----- .../intellij/execution/ui/JrePathEditor.java | 58 +++++++--- .../service/ui/ExternalProjectPathField.java | 3 +- .../ui/CommonProgramParametersPanel.java | 4 +- .../ui/MacroComboBoxWithBrowseButton.java | 50 ++++---- .../openapi/ui/BrowseFolderRunnable.java | 109 ++++++++++++++++++ .../openapi/ui/ComponentWithBrowseButton.java | 88 +------------- .../openapi/ui/TextBrowseFolderListener.java | 2 +- .../intellij/ui/components/JBTextField.java | 1 + .../fields/ExtendableTextField.java | 33 ++++++ .../com/intellij/ui/components/components.kt | 2 +- .../config/execution/AntRunConfiguration.java | 40 +++---- 12 files changed, 248 insertions(+), 179 deletions(-) create mode 100644 platform/platform-api/src/com/intellij/openapi/ui/BrowseFolderRunnable.java diff --git a/java/execution/impl/src/com/intellij/execution/ui/JreComboboxEditor.java b/java/execution/impl/src/com/intellij/execution/ui/JreComboboxEditor.java index ee58ebebb89d..f1618c66bb6a 100644 --- a/java/execution/impl/src/com/intellij/execution/ui/JreComboboxEditor.java +++ b/java/execution/impl/src/com/intellij/execution/ui/JreComboboxEditor.java @@ -15,6 +15,7 @@ */ package com.intellij.execution.ui; +import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.openapi.util.io.FileUtil; import com.intellij.ui.SortedComboBoxModel; @@ -22,17 +23,13 @@ import com.intellij.ui.components.JBTextField; import com.intellij.util.ui.StatusText; import org.jetbrains.annotations.NotNull; -import javax.swing.*; import javax.swing.plaf.basic.BasicComboBoxEditor; -import java.awt.*; -import java.awt.event.FocusEvent; -import java.awt.event.FocusListener; /** * @author nik */ class JreComboboxEditor extends BasicComboBoxEditor { - public static final TextComponentAccessor TEXT_COMPONENT_ACCESSOR = new JreComboBoxTextComponentAccessor(); + public static final TextComponentAccessor> TEXT_COMPONENT_ACCESSOR = new JreComboBoxTextComponentAccessor(); private final SortedComboBoxModel myComboBoxModel; JreComboboxEditor(SortedComboBoxModel comboBoxModel) { @@ -55,30 +52,6 @@ class JreComboboxEditor extends BasicComboBoxEditor { return new JrePathEditor.CustomJreItem(FileUtil.toSystemIndependentName(text)); } - @Override - protected JTextField createEditorComponent() { - JBTextField field = new JBTextField(); - field.setBorder(null); - field.addFocusListener(new FocusListener() { - @Override public void focusGained(FocusEvent e) { - update(e); - } - @Override public void focusLost(FocusEvent e) { - update(e); - } - - private void update(FocusEvent e) { - Component c = e.getComponent().getParent(); - if (c != null) { - c.revalidate(); - c.repaint(); - } - } - }); - - return field; - } - public StatusText getEmptyText() { return getEditorComponent().getEmptyText(); } @@ -88,15 +61,15 @@ class JreComboboxEditor extends BasicComboBoxEditor { return (JBTextField)super.getEditorComponent(); } - private static class JreComboBoxTextComponentAccessor implements TextComponentAccessor { + private static class JreComboBoxTextComponentAccessor implements TextComponentAccessor> { @Override - public String getText(JComboBox component) { + public String getText(ComboBox component) { Object item = component.getEditor().getItem(); return item != null ? ((JrePathEditor.JreComboBoxItem)item).getPresentableText() : ""; } @Override - public void setText(JComboBox component, @NotNull String text) { + public void setText(ComboBox component, @NotNull String text) { component.getEditor().setItem(new JrePathEditor.CustomJreItem(FileUtil.toSystemIndependentName(text))); } } diff --git a/java/execution/impl/src/com/intellij/execution/ui/JrePathEditor.java b/java/execution/impl/src/com/intellij/execution/ui/JrePathEditor.java index 201af6b8deaf..052487aff8a8 100644 --- a/java/execution/impl/src/com/intellij/execution/ui/JrePathEditor.java +++ b/java/execution/impl/src/com/intellij/execution/ui/JrePathEditor.java @@ -7,6 +7,7 @@ import com.intellij.ide.util.BrowseFilesListener; import com.intellij.openapi.projectRoots.ProjectJdkTable; import com.intellij.openapi.projectRoots.Sdk; import com.intellij.openapi.roots.ui.OrderEntryAppearanceService; +import com.intellij.openapi.ui.BrowseFolderRunnable; import com.intellij.openapi.ui.ComboBox; import com.intellij.openapi.ui.LabeledComponent; import com.intellij.openapi.util.Comparing; @@ -14,6 +15,8 @@ import com.intellij.openapi.util.SystemInfo; import com.intellij.openapi.util.io.FileUtil; import com.intellij.openapi.util.text.StringUtil; import com.intellij.ui.*; +import com.intellij.ui.components.JBTextField; +import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.util.ui.JBUI; import com.intellij.util.ui.StatusText; import org.jetbrains.annotations.NotNull; @@ -22,6 +25,8 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; import java.awt.event.ActionListener; +import java.awt.event.FocusEvent; +import java.awt.event.FocusListener; import java.io.File; import java.util.HashSet; import java.util.Set; @@ -29,7 +34,7 @@ import java.util.Set; /** * @author nik */ -public class JrePathEditor extends LabeledComponent implements PanelWithAnchor { +public class JrePathEditor extends LabeledComponent implements PanelWithAnchor { private static final String DEFAULT_JRE_TEXT = "Default"; private final JreComboboxEditor myComboboxEditor; private final DefaultJreItem myDefaultJreItem; @@ -101,20 +106,47 @@ public class JrePathEditor extends LabeledComponent im } } }); - myComboboxEditor = new JreComboboxEditor(myComboBoxModel); - myComboboxEditor.getEditorComponent().setTextToTriggerEmptyTextStatus(DEFAULT_JRE_TEXT); + + Runnable action = new BrowseFolderRunnable<>(ExecutionBundle.message("run.configuration.select.alternate.jre.label"), + ExecutionBundle.message("run.configuration.select.jre.dir.label"), + null, + BrowseFilesListener.SINGLE_DIRECTORY_DESCRIPTOR, + comboBox, + JreComboboxEditor.TEXT_COMPONENT_ACCESSOR); + + myComboboxEditor = new JreComboboxEditor(myComboBoxModel) { + @Override + protected JTextField createEditorComponent() { + JBTextField field = ExtendableTextField.createBrowsableField(action, null); + field.setBorder(null); + field.addFocusListener(new FocusListener() { + @Override public void focusGained(FocusEvent e) { + update(e); + } + @Override public void focusLost(FocusEvent e) { + update(e); + } + + private void update(FocusEvent e) { + Component c = e.getComponent().getParent(); + if (c != null) { + c.revalidate(); + c.repaint(); + } + } + }); + field.setTextToTriggerEmptyTextStatus(DEFAULT_JRE_TEXT); + + return field; + } + + }; comboBox.setEditor(myComboboxEditor); InsertPathAction.addTo(myComboboxEditor.getEditorComponent()); - ComboboxWithBrowseButton pathField = new ComboboxWithBrowseButton(comboBox); - pathField.addBrowseFolderListener(ExecutionBundle.message("run.configuration.select.alternate.jre.label"), - ExecutionBundle.message("run.configuration.select.jre.dir.label"), - null, BrowseFilesListener.SINGLE_DIRECTORY_DESCRIPTOR, - JreComboboxEditor.TEXT_COMPONENT_ACCESSOR); - setLabelLocation(BorderLayout.WEST); setText(ExecutionBundle.message("run.configuration.jre.label")); - setComponent(pathField); + setComponent(comboBox); updateUI(); } @@ -133,7 +165,7 @@ public class JrePathEditor extends LabeledComponent im } private JreComboBoxItem getSelectedJre() { - return (JreComboBoxItem)getComponent().getComboBox().getEditor().getItem(); + return (JreComboBoxItem)getComponent().getEditor().getItem(); } public void setDefaultJreSelector(DefaultJreSelector defaultJreSelector) { @@ -150,7 +182,7 @@ public class JrePathEditor extends LabeledComponent im toSelect = alternative; } } - getComponent().getChildComponent().setSelectedItem(toSelect); + getComponent().setSelectedItem(toSelect); updateDefaultJrePresentation(); } @@ -174,7 +206,7 @@ public class JrePathEditor extends LabeledComponent im } public void addActionListener(ActionListener listener) { - getComponent().getComboBox().addActionListener(listener); + getComponent().addActionListener(listener); } interface JreComboBoxItem { diff --git a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalProjectPathField.java b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalProjectPathField.java index 575f2674c122..770eddd8ded4 100644 --- a/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalProjectPathField.java +++ b/platform/external-system-impl/src/com/intellij/openapi/externalSystem/service/ui/ExternalProjectPathField.java @@ -172,11 +172,10 @@ public class ExternalProjectPathField extends ComponentWithBrowseButton { + EditorTextField result = provider.createEditor(project, true, editor -> { collapseIfPossible(editor, externalSystemId, project); editor.getSettings().setShowIntentionBulb(false); }); - result.setBorder(UIUtil.getTextFieldBorder()); result.setOneLineMode(true); result.setOpaque(true); result.setBackground(UIUtil.getTextFieldBackground()); diff --git a/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java b/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java index d942db2ddc2c..d7b6b6c2ce0b 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/CommonProgramParametersPanel.java @@ -104,7 +104,7 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc @Override public void actionPerformed(ActionEvent e) { List macros = new ArrayList<>(); - ComboBoxModel model = myWorkingDirectoryComboBox.getChildComponent().getModel(); + ComboBoxModel model = myWorkingDirectoryComboBox.getModel(); for (int i = 0; i < model.getSize(); ++i) { macros.add(model.getElementAt(i)); } @@ -150,7 +150,7 @@ public class CommonProgramParametersPanel extends JPanel implements PanelWithAnc } public void addWorkingDirectoryListener(Consumer onTextChange) { - myWorkingDirectoryComboBox.getChildComponent().addActionListener(event -> onTextChange.accept(myWorkingDirectoryComboBox.getText())); + myWorkingDirectoryComboBox.addActionListener(event -> onTextChange.accept(myWorkingDirectoryComboBox.getText())); } public void setWorkingDirectory(String dir) { diff --git a/platform/lang-impl/src/com/intellij/execution/ui/MacroComboBoxWithBrowseButton.java b/platform/lang-impl/src/com/intellij/execution/ui/MacroComboBoxWithBrowseButton.java index 50742ae4b8c9..46846efa07ab 100644 --- a/platform/lang-impl/src/com/intellij/execution/ui/MacroComboBoxWithBrowseButton.java +++ b/platform/lang-impl/src/com/intellij/execution/ui/MacroComboBoxWithBrowseButton.java @@ -21,29 +21,30 @@ import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.fileChooser.FileChooserFactory; import com.intellij.openapi.module.Module; import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.BrowseFolderRunnable; import com.intellij.openapi.ui.ComboBox; -import com.intellij.openapi.ui.ComponentWithBrowseButton; import com.intellij.openapi.ui.TextComponentAccessor; import com.intellij.ui.TextAccessor; +import com.intellij.ui.components.fields.ExtendableTextField; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import javax.swing.*; -import java.awt.Component; +import javax.swing.plaf.basic.BasicComboBoxEditor; +import java.awt.*; -public class MacroComboBoxWithBrowseButton extends ComponentWithBrowseButton> implements TextAccessor { +public class MacroComboBoxWithBrowseButton extends ComboBox implements TextAccessor { private Module module; private boolean always; public MacroComboBoxWithBrowseButton(FileChooserDescriptor descriptor, Project project) { - super(new ComboBox<>(new MacroComboBoxModel()), null); + super(new MacroComboBoxModel()); - ComboBox combobox = getChildComponent(); - combobox.setEditable(true); + setEditable(true); descriptor.withShowHiddenFiles(true); - addActionListener(new BrowseFolderActionListener>(null, null, this, project, descriptor, accessor) { + + Runnable action = new BrowseFolderRunnable>(null, null, project, descriptor, this, accessor) { private Module getModule() { - Module module = MacroComboBoxWithBrowseButton.this.module; if (module == null) module = myFileChooserDescriptor.getUserData(LangDataKeys.MODULE_CONTEXT); if (module == null) module = myFileChooserDescriptor.getUserData(LangDataKeys.MODULE); return module; @@ -69,29 +70,32 @@ public class MacroComboBoxWithBrowseButton extends ComponentWithBrowseButton model = getChildComponent().getModel(); - return model instanceof MacroComboBoxModel ? (MacroComboBoxModel)model : null; + ComboBoxEditor editor = new BasicComboBoxEditor() { + @Override + protected JTextField createEditorComponent() { + JTextField editor = ExtendableTextField.createBrowsableField(action, project); + editor.setBorder(null); + return editor; + } + }; + setEditor(editor); + + Component component = editor.getEditorComponent(); + if (component instanceof JTextField) { + FileChooserFactory.getInstance().installFileCompletion((JTextField)component, descriptor, true, null); + } } @Override public String getText() { - return accessor.getText(getChildComponent()); + return accessor.getText(this); } @Override public void setText(String text) { - accessor.setText(getChildComponent(), text != null ? text : ""); + accessor.setText(this, text != null ? text : ""); } public void setModule(Module module) { @@ -105,7 +109,7 @@ public class MacroComboBoxWithBrowseButton extends ComponentWithBrowseButton implements Runnable { + private final String myTitle; + private final String myDescription; + protected final TextComponentAccessor myAccessor; + protected final FileChooserDescriptor myFileChooserDescriptor; + + protected T myTextComponent; + private Project myProject; + + public BrowseFolderRunnable(@Nullable @Nls(capitalization = Nls.Capitalization.Title) String title, + @Nullable @Nls(capitalization = Nls.Capitalization.Sentence) String description, + @Nullable Project project, + FileChooserDescriptor fileChooserDescriptor, + @Nullable T component, + TextComponentAccessor accessor) { + if (fileChooserDescriptor != null && fileChooserDescriptor.isChooseMultiple()) { + //LOG.error("multiple selection not supported"); + fileChooserDescriptor = new FileChooserDescriptor(fileChooserDescriptor) { + @Override + public boolean isChooseMultiple() { + return false; + } + }; + } + + myTitle = title; + myDescription = description; + myTextComponent = component; + myProject = project; + myFileChooserDescriptor = fileChooserDescriptor; + myAccessor = accessor; + } + + @Nullable + protected Project getProject() { + return myProject; + } + + protected void setProject(@Nullable Project project) { + myProject = project; + } + + @Override + public void run() { + FileChooserDescriptor fileChooserDescriptor = myFileChooserDescriptor; + if (myTitle != null || myDescription != null) { + fileChooserDescriptor = (FileChooserDescriptor)myFileChooserDescriptor.clone(); + if (myTitle != null) { + fileChooserDescriptor.setTitle(myTitle); + } + if (myDescription != null) { + fileChooserDescriptor.setDescription(myDescription); + } + } + + FileChooser.chooseFile(fileChooserDescriptor, getProject(), myTextComponent, getInitialFile(), + vf -> myAccessor.setText(myTextComponent, chosenFileToResultingText(vf))); + } + + @Nullable + protected VirtualFile getInitialFile() { + String directoryName = myAccessor.getText(myTextComponent).trim(); + if (StringUtil.isEmptyOrSpaces(directoryName)) { + return null; + } + + directoryName = FileUtil.toSystemIndependentName(directoryName); + VirtualFile path = LocalFileSystem.getInstance().findFileByPath(expandPath(directoryName)); + while (path == null && directoryName.length() > 0) { + int pos = directoryName.lastIndexOf('/'); + if (pos <= 0) break; + directoryName = directoryName.substring(0, pos); + path = LocalFileSystem.getInstance().findFileByPath(directoryName); + } + return path; + } + + @NotNull + protected String expandPath(@NotNull String path) { + return path; + } + + @NotNull + protected String chosenFileToResultingText(@NotNull VirtualFile chosenFile) { + return chosenFile.getPresentableUrl(); + } + + protected String getComponentText() { + return myAccessor.getText(myTextComponent).trim(); + } +} diff --git a/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java b/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java index 55d69c3647b9..d18f5479ede2 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/ComponentWithBrowseButton.java @@ -9,16 +9,12 @@ import com.intellij.openapi.actionSystem.ShortcutSet; import com.intellij.openapi.application.ApplicationManager; import com.intellij.openapi.application.Experiments; import com.intellij.openapi.diagnostic.Logger; -import com.intellij.openapi.fileChooser.FileChooser; import com.intellij.openapi.fileChooser.FileChooserDescriptor; import com.intellij.openapi.keymap.KeymapUtil; import com.intellij.openapi.project.DumbAwareAction; import com.intellij.openapi.project.Project; import com.intellij.openapi.util.IconLoader; import com.intellij.openapi.util.SystemInfo; -import com.intellij.openapi.util.io.FileUtil; -import com.intellij.openapi.util.text.StringUtil; -import com.intellij.openapi.vfs.LocalFileSystem; import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.wm.IdeFocusManager; import com.intellij.ui.GuiUtils; @@ -219,97 +215,23 @@ public class ComponentWithBrowseButton extends JPanel i } } - public static class BrowseFolderActionListener implements ActionListener { - private final String myTitle; - private final String myDescription; - protected ComponentWithBrowseButton myTextComponent; - private final TextComponentAccessor myAccessor; - private Project myProject; - protected final FileChooserDescriptor myFileChooserDescriptor; - + public static class BrowseFolderActionListener extends BrowseFolderRunnable implements ActionListener { public BrowseFolderActionListener(@Nullable @Nls(capitalization = Nls.Capitalization.Title) String title, @Nullable @Nls(capitalization = Nls.Capitalization.Sentence) String description, - ComponentWithBrowseButton textField, + @Nullable ComponentWithBrowseButton textField, @Nullable Project project, FileChooserDescriptor fileChooserDescriptor, TextComponentAccessor accessor) { - if (fileChooserDescriptor != null && fileChooserDescriptor.isChooseMultiple()) { - LOG.error("multiple selection not supported"); - fileChooserDescriptor = new FileChooserDescriptor(fileChooserDescriptor) { - @Override - public boolean isChooseMultiple() { - return false; - } - }; - } - - myTitle = title; - myDescription = description; - myTextComponent = textField; - myProject = project; - myFileChooserDescriptor = fileChooserDescriptor; - myAccessor = accessor; - } - - @Nullable - protected Project getProject() { - return myProject; - } - - protected void setProject(@Nullable Project project) { - myProject = project; + super(title, description, project, fileChooserDescriptor, textField != null ? textField.getChildComponent() : null, accessor); } @Override public void actionPerformed(ActionEvent e) { - FileChooserDescriptor fileChooserDescriptor = myFileChooserDescriptor; - if (myTitle != null || myDescription != null) { - fileChooserDescriptor = (FileChooserDescriptor)myFileChooserDescriptor.clone(); - if (myTitle != null) { - fileChooserDescriptor.setTitle(myTitle); - } - if (myDescription != null) { - fileChooserDescriptor.setDescription(myDescription); - } - } - - FileChooser.chooseFile(fileChooserDescriptor, getProject(), myTextComponent, getInitialFile(), this::onFileChosen); - } - - @Nullable - protected VirtualFile getInitialFile() { - String directoryName = getComponentText(); - if (StringUtil.isEmptyOrSpaces(directoryName)) { - return null; - } - - directoryName = FileUtil.toSystemIndependentName(directoryName); - VirtualFile path = LocalFileSystem.getInstance().findFileByPath(expandPath(directoryName)); - while (path == null && directoryName.length() > 0) { - int pos = directoryName.lastIndexOf('/'); - if (pos <= 0) break; - directoryName = directoryName.substring(0, pos); - path = LocalFileSystem.getInstance().findFileByPath(directoryName); - } - return path; - } - - @NotNull - protected String expandPath(@NotNull String path) { - return path; - } - - protected String getComponentText() { - return myAccessor.getText(myTextComponent.getChildComponent()).trim(); - } - - @NotNull - protected String chosenFileToResultingText(@NotNull VirtualFile chosenFile) { - return chosenFile.getPresentableUrl(); + run(); } protected void onFileChosen(@NotNull VirtualFile chosenFile) { - myAccessor.setText(myTextComponent.getChildComponent(), chosenFileToResultingText(chosenFile)); + myAccessor.setText(myTextComponent, chosenFileToResultingText(chosenFile)); } } diff --git a/platform/platform-api/src/com/intellij/openapi/ui/TextBrowseFolderListener.java b/platform/platform-api/src/com/intellij/openapi/ui/TextBrowseFolderListener.java index 8064d19d8843..23cd7821a9b0 100644 --- a/platform/platform-api/src/com/intellij/openapi/ui/TextBrowseFolderListener.java +++ b/platform/platform-api/src/com/intellij/openapi/ui/TextBrowseFolderListener.java @@ -32,7 +32,7 @@ public class TextBrowseFolderListener extends ComponentWithBrowseButton.BrowseFo } void setOwnerComponent(@NotNull TextFieldWithBrowseButton component) { - myTextComponent = component; + myTextComponent = component.getChildComponent(); } FileChooserDescriptor getFileChooserDescriptor() { diff --git a/platform/platform-api/src/com/intellij/ui/components/JBTextField.java b/platform/platform-api/src/com/intellij/ui/components/JBTextField.java index 8d0ed14c5d63..193cdd3ccce5 100644 --- a/platform/platform-api/src/com/intellij/ui/components/JBTextField.java +++ b/platform/platform-api/src/com/intellij/ui/components/JBTextField.java @@ -99,6 +99,7 @@ public class JBTextField extends JTextField implements ComponentWithEmptyText, T Rectangle rect = new Rectangle(getSize()); JBInsets.removeFrom(rect, getInsets()); + JBInsets.removeFrom(rect, getMargin()); ((Graphics2D)g).fill(rect); g.setColor(getForeground()); diff --git a/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java b/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java index 391da221ae0d..e27b5c0f4ea8 100644 --- a/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java +++ b/platform/platform-api/src/com/intellij/ui/components/fields/ExtendableTextField.java @@ -1,12 +1,23 @@ // Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. package com.intellij.ui.components.fields; +import com.intellij.icons.AllIcons; +import com.intellij.openapi.Disposable; +import com.intellij.openapi.actionSystem.AnActionEvent; +import com.intellij.openapi.actionSystem.CustomShortcutSet; +import com.intellij.openapi.keymap.KeymapUtil; +import com.intellij.openapi.project.DumbAwareAction; +import com.intellij.ui.UIBundle; import com.intellij.ui.components.JBTextField; +import org.jetbrains.annotations.ApiStatus; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import javax.swing.*; import javax.swing.border.Border; import javax.swing.plaf.TextUI; +import java.awt.event.InputEvent; +import java.awt.event.KeyEvent; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -103,4 +114,26 @@ public class ExtendableTextField extends JBTextField implements ExtendableTextCo } } } + + @ApiStatus.Experimental + public static ExtendableTextField createBrowsableField(@NotNull Runnable action, @Nullable Disposable parentDisposable) { + ExtendableTextField field = new ExtendableTextField(); + + KeyStroke keyStroke = KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, InputEvent.SHIFT_DOWN_MASK); + String tooltip = UIBundle.message("component.with.browse.button.browse.button.tooltip.text") + + " (" + KeymapUtil.getKeystrokeText(keyStroke) + ")"; + + ExtendableTextComponent.Extension browseExtension = + ExtendableTextComponent.Extension.create(AllIcons.General.OpenDisk, AllIcons.General.OpenDiskHover, tooltip, action); + + new DumbAwareAction() { + @Override + public void actionPerformed(@NotNull AnActionEvent e) { + action.run(); + } + }.registerCustomShortcutSet(new CustomShortcutSet(keyStroke), field, parentDisposable); + field.addExtension(browseExtension); + + return field; + } } diff --git a/platform/platform-impl/src/com/intellij/ui/components/components.kt b/platform/platform-impl/src/com/intellij/ui/components/components.kt index d0eae26c068a..04c96f26bee8 100644 --- a/platform/platform-impl/src/com/intellij/ui/components/components.kt +++ b/platform/platform-impl/src/com/intellij/ui/components/components.kt @@ -238,7 +238,7 @@ fun installFileCompletionAndBrowseDialog(project: Project?, super.onFileChosen(chosenFile) } else { - textComponentAccessor.setText(myTextComponent.childComponent, fileChosen(chosenFile)) + textComponentAccessor.setText(myTextComponent, fileChosen(chosenFile)) } } }) diff --git a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunConfiguration.java b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunConfiguration.java index d009a25b256f..07efdb08b9bd 100644 --- a/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunConfiguration.java +++ b/plugins/ant/src/com/intellij/lang/ant/config/execution/AntRunConfiguration.java @@ -13,12 +13,12 @@ import com.intellij.lang.ant.config.impl.TargetChooserDialog; import com.intellij.openapi.options.SettingsEditor; import com.intellij.openapi.project.Project; import com.intellij.openapi.ui.LabeledComponent; -import com.intellij.openapi.ui.TextFieldWithBrowseButton; import com.intellij.openapi.util.InvalidDataException; import com.intellij.openapi.util.JDOMExternalizable; import com.intellij.openapi.util.WriteExternalException; import com.intellij.openapi.util.text.StringUtil; import com.intellij.openapi.vfs.VirtualFile; +import com.intellij.ui.components.fields.ExtendableTextField; import com.intellij.util.containers.ContainerUtil; import com.intellij.util.ui.ColumnInfo; import com.intellij.util.ui.ListTableModel; @@ -28,8 +28,6 @@ import org.jetbrains.annotations.Nullable; import javax.swing.*; import java.awt.*; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; import java.util.ArrayList; import java.util.Collections; import java.util.List; @@ -171,27 +169,24 @@ public final class AntRunConfiguration extends LocatableConfigurationBase implem private String myFileUrl = null; private String myTargetName = null; - private final JTextField myTextField = new JTextField(); + private ExtendableTextField myTextField; private final PropertiesTable myPropTable = new PropertiesTable(); - private final ActionListener myActionListener = new ActionListener() { - @Override - public void actionPerformed(ActionEvent e) { - AntBuildTarget buildTarget = getTarget(); - final TargetChooserDialog dlg = new TargetChooserDialog(getProject(), buildTarget); - if (dlg.showAndGet()) { - myFileUrl = null; - myTargetName = null; - buildTarget = dlg.getSelectedTarget(); - if (buildTarget != null) { - final VirtualFile vFile = buildTarget.getModel().getBuildFile().getVirtualFile(); - if (vFile != null) { - myFileUrl = vFile.getUrl(); - myTargetName = buildTarget.getName(); - } + private final Runnable myAction = () -> { + AntBuildTarget buildTarget = getTarget(); + final TargetChooserDialog dlg = new TargetChooserDialog(getProject(), buildTarget); + if (dlg.showAndGet()) { + myFileUrl = null; + myTargetName = null; + buildTarget = dlg.getSelectedTarget(); + if (buildTarget != null) { + final VirtualFile vFile = buildTarget.getModel().getBuildFile().getVirtualFile(); + if (vFile != null) { + myFileUrl = vFile.getUrl(); + myTargetName = buildTarget.getName(); } - updateUI(); } + updateUI(); } }; @@ -224,9 +219,10 @@ public final class AntRunConfiguration extends LocatableConfigurationBase implem @NotNull @Override protected JComponent createEditor() { - myTextField.setEditable(false); + myTextField = ExtendableTextField.createBrowsableField(myAction, this); + final JPanel panel = new JPanel(new BorderLayout()); - panel.add(LabeledComponent.create(new TextFieldWithBrowseButton(myTextField, myActionListener), "Target name", BorderLayout.WEST), BorderLayout.NORTH); + panel.add(LabeledComponent.create(myTextField, "Target name", BorderLayout.WEST), BorderLayout.NORTH); final LabeledComponent tableComponent = LabeledComponent.create(myPropTable.getComponent(), "Ant Properties"); tableComponent.setBorder(BorderFactory.createEmptyBorder(10, 0, 0, 0));