ComponentWithBrowseButton - optional remove listener on hide
[fedora-idea.git] / platform / platform-api / src / com / intellij / openapi / ui / ComponentWithBrowseButton.java
blob9e7943e7a8d33e85c3b14e91b2ccc1dd3efbae51
1 /*
2 * Copyright 2000-2009 JetBrains s.r.o.
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
16 package com.intellij.openapi.ui;
18 import com.intellij.openapi.Disposable;
19 import com.intellij.openapi.actionSystem.AnAction;
20 import com.intellij.openapi.actionSystem.AnActionEvent;
21 import com.intellij.openapi.actionSystem.CustomShortcutSet;
22 import com.intellij.openapi.actionSystem.ShortcutSet;
23 import com.intellij.openapi.application.ApplicationManager;
24 import com.intellij.openapi.fileChooser.FileChooser;
25 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
26 import com.intellij.openapi.keymap.KeymapUtil;
27 import com.intellij.openapi.project.Project;
28 import com.intellij.openapi.util.Disposer;
29 import com.intellij.openapi.util.SystemInfo;
30 import com.intellij.openapi.vfs.LocalFileSystem;
31 import com.intellij.openapi.vfs.VirtualFile;
32 import com.intellij.ui.UIBundle;
33 import com.intellij.util.ui.update.LazyUiDisposable;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
37 import javax.swing.*;
38 import java.awt.*;
39 import java.awt.event.ActionEvent;
40 import java.awt.event.ActionListener;
41 import java.awt.event.KeyEvent;
42 import java.io.File;
44 public class ComponentWithBrowseButton<Comp extends JComponent> extends JPanel implements Disposable {
45 private final Comp myComponent;
46 private final FixedSizeButton myBrowseButton;
47 private boolean myButtonEnabled = true;
49 public ComponentWithBrowseButton(Comp component, ActionListener browseActionListener) {
50 super(new BorderLayout(SystemInfo.isMac? 0 : 2, 0));
51 myComponent = component;
52 add(myComponent, BorderLayout.CENTER);
54 myBrowseButton=new FixedSizeButton(myComponent);
55 if (browseActionListener != null)
56 myBrowseButton.addActionListener(browseActionListener);
57 add(myBrowseButton, BorderLayout.EAST);
59 myBrowseButton.setToolTipText(UIBundle.message("component.with.browse.button.browse.button.tooltip.text"));
61 // FixedSizeButton isn't focusable but it should be selectable via keyboard.
62 if (ApplicationManager.getApplication() != null) { // avoid crash at design time
63 new MyDoClickAction(myBrowseButton).registerShortcut(myComponent);
67 public final Comp getChildComponent() {
68 return myComponent;
71 public void setTextFieldPreferredWidth(final int charCount) {
72 final Comp comp = getChildComponent();
73 Dimension size = comp.getPreferredSize();
74 FontMetrics fontMetrics = comp.getFontMetrics(comp.getFont());
75 size.width = fontMetrics.charWidth('a') * charCount;
76 comp.setPreferredSize(size);
77 final Dimension preferredSize = myBrowseButton.getPreferredSize();
78 setPreferredSize(new Dimension(size.width + preferredSize.width + 2, preferredSize.height + 2));
81 public void setEnabled(boolean enabled) {
82 super.setEnabled(enabled);
83 myBrowseButton.setEnabled(enabled && myButtonEnabled);
84 myComponent.setEnabled(enabled);
87 public void setButtonEnabled(boolean buttonEnabled) {
88 myButtonEnabled = buttonEnabled;
89 setEnabled(isEnabled());
92 public void setButtonIcon(Icon icon) {
93 myBrowseButton.setIcon(icon);
96 /**
97 * Adds specified <code>listener</code> to the browse button.
99 public void addActionListener(ActionListener listener){
100 myBrowseButton.addActionListener(listener);
103 public void removeActionListener(ActionListener listener) {
104 myBrowseButton.removeActionListener(listener);
107 public void addBrowseFolderListener(String title, String description, @Nullable Project project,
108 FileChooserDescriptor fileChooserDescriptor,
109 TextComponentAccessor<Comp> accessor) {
110 addBrowseFolderListener(title, description, project, fileChooserDescriptor, accessor, true);
113 public void addBrowseFolderListener(String title, String description, @Nullable Project project,
114 FileChooserDescriptor fileChooserDescriptor,
115 TextComponentAccessor<Comp> accessor, boolean autoRemoveOnHide) {
116 addBrowseFolderListener(project, new BrowseFolderActionListener<Comp>(title, description, this, project, fileChooserDescriptor, accessor), autoRemoveOnHide);
119 public void addBrowseFolderListener(@Nullable Project project, final BrowseFolderActionListener<Comp> actionListener) {
120 addBrowseFolderListener(project, actionListener, true);
123 public void addBrowseFolderListener(@Nullable Project project, final BrowseFolderActionListener<Comp> actionListener, boolean autoRemoveOnHide) {
124 if (autoRemoveOnHide) {
125 new LazyUiDisposable<ComponentWithBrowseButton<Comp>>(null, this, this) {
126 protected void initialize(@NotNull Disposable parent, @NotNull ComponentWithBrowseButton<Comp> child, @Nullable Project project) {
127 addActionListener(actionListener);
128 Disposer.register(child, new Disposable() {
129 public void dispose() {
130 removeActionListener(actionListener);
135 } else {
136 addActionListener(actionListener);
140 public void dispose() {
143 public FixedSizeButton getButton() {
144 return myBrowseButton;
148 * Do not use this class directly it is public just to hack other implementation of controls similar to TextFieldWithBrowseButton.
150 public static final class MyDoClickAction extends AnAction{
151 private final FixedSizeButton myBrowseButton;
152 private JComponent myFocusedComponent;
153 public MyDoClickAction(FixedSizeButton browseButton) {
154 myBrowseButton = browseButton;
157 public void actionPerformed(AnActionEvent e){
158 myBrowseButton.doClick();
159 SwingUtilities.invokeLater(new Runnable() {
160 public void run() {
161 if (myFocusedComponent != null){
162 myFocusedComponent.requestFocus();
169 public void registerShortcut(JComponent textField) {
170 ShortcutSet shiftEnter = new CustomShortcutSet(KeyStroke.getKeyStroke(KeyEvent.VK_ENTER, KeyEvent.SHIFT_DOWN_MASK));
171 registerCustomShortcutSet(shiftEnter, textField);
172 myBrowseButton.setToolTipText(KeymapUtil.getShortcutsText(shiftEnter.getShortcuts()));
173 myFocusedComponent = textField;
176 public static void addTo(FixedSizeButton browseButton, JComponent aComponent) {
177 new MyDoClickAction(browseButton).registerShortcut(aComponent);
181 public static class BrowseFolderActionListener<T extends JComponent> implements ActionListener {
182 private final String myTitle;
183 private final String myDescription;
184 private final ComponentWithBrowseButton<T> myTextComponent;
185 private final TextComponentAccessor<T> myAccessor;
186 private final Project myProject;
187 private final FileChooserDescriptor myFileChooserDescriptor;
189 public BrowseFolderActionListener(String title, String description, ComponentWithBrowseButton<T> textField, @Nullable Project project, FileChooserDescriptor fileChooserDescriptor, TextComponentAccessor<T> accessor) {
190 myTitle = title;
191 myDescription = description;
192 myTextComponent = textField;
193 myProject = project;
194 myFileChooserDescriptor = fileChooserDescriptor;
195 myAccessor = accessor;
198 public void actionPerformed(ActionEvent e){
199 FileChooserDescriptor fileChooserDescriptor = (FileChooserDescriptor)myFileChooserDescriptor.clone();
200 if (myTitle != null) {
201 fileChooserDescriptor.setTitle(myTitle);
203 if (myDescription != null) {
204 fileChooserDescriptor.setDescription(myDescription);
206 VirtualFile initialFile = getInitialFile();
207 VirtualFile[] files = doChoose(fileChooserDescriptor, initialFile);
208 if (files != null && files.length != 0) {
209 onFileChoosen(files[0]);
213 @Nullable
214 protected VirtualFile getInitialFile() {
215 String directoryName = getComponentText();
216 if (directoryName.length() == 0) return null;
217 directoryName = directoryName.replace(File.separatorChar, '/');
218 VirtualFile path = LocalFileSystem.getInstance().findFileByPath(directoryName);
219 while (path == null && directoryName.length() > 0) {
220 int pos = directoryName.lastIndexOf('/');
221 if (pos <= 0) break;
222 directoryName = directoryName.substring(0, pos-1);
223 path = LocalFileSystem.getInstance().findFileByPath(directoryName);
225 return path;
228 protected String getComponentText() {
229 return myAccessor.getText(myTextComponent.getChildComponent()).trim();
232 protected void onFileChoosen(VirtualFile chosenFile) {
233 myAccessor.setText(myTextComponent.getChildComponent(), chosenFile.getPresentableUrl());
236 private VirtualFile[] doChoose(FileChooserDescriptor fileChooserDescriptor, VirtualFile initialFile) {
237 if (myProject == null) {
238 return FileChooser.chooseFiles(myTextComponent, fileChooserDescriptor, initialFile);
240 else {
241 return FileChooser.chooseFiles(myProject, fileChooserDescriptor, initialFile);
246 public final void requestFocus() {
247 myComponent.requestFocus();
250 public final void setNextFocusableComponent(Component aComponent) {
251 myComponent.setNextFocusableComponent(aComponent);
254 private KeyEvent myCurrentEvent = null;
255 protected final boolean processKeyBinding(KeyStroke ks, KeyEvent e, int condition, boolean pressed) {
256 if (condition == WHEN_FOCUSED && myCurrentEvent != e)
257 try {
258 myCurrentEvent = e;
259 myComponent.dispatchEvent(e);
261 finally {
262 myCurrentEvent = null;
264 if (e.isConsumed()) return true;
265 return super.processKeyBinding(ks, e, condition, pressed);