combobox with browse button with path completion; recent manager to be used (IDEA...
[idea/community.git] / platform / lang-impl / src / com / intellij / refactoring / move / moveFilesOrDirectories / MoveFilesOrDirectoriesDialog.java
1 /*
2  * Copyright 2000-2009 JetBrains s.r.o.
3  *
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
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
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.
15  */
16
17 package com.intellij.refactoring.move.moveFilesOrDirectories;
18
19 import com.intellij.ide.util.DirectoryUtil;
20 import com.intellij.openapi.actionSystem.ActionManager;
21 import com.intellij.openapi.actionSystem.IdeActions;
22 import com.intellij.openapi.application.ApplicationManager;
23 import com.intellij.openapi.command.CommandProcessor;
24 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
25 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
26 import com.intellij.openapi.fileChooser.FileChooserFactory;
27 import com.intellij.openapi.help.HelpManager;
28 import com.intellij.openapi.keymap.KeymapUtil;
29 import com.intellij.openapi.project.Project;
30 import com.intellij.openapi.ui.DialogWrapper;
31 import com.intellij.openapi.ui.TextComponentAccessor;
32 import com.intellij.openapi.util.Disposer;
33 import com.intellij.psi.PsiDirectory;
34 import com.intellij.psi.PsiElement;
35 import com.intellij.psi.PsiFile;
36 import com.intellij.psi.PsiManager;
37 import com.intellij.refactoring.RefactoringBundle;
38 import com.intellij.refactoring.RefactoringSettings;
39 import com.intellij.refactoring.util.CommonRefactoringUtil;
40 import com.intellij.ui.DocumentAdapter;
41 import com.intellij.ui.NonFocusableCheckBox;
42 import com.intellij.ui.RecentsManager;
43 import com.intellij.ui.TextFieldWithHistoryWithBrowseButton;
44 import com.intellij.util.IncorrectOperationException;
45 import com.intellij.util.ui.UIUtil;
46 import org.jetbrains.annotations.NonNls;
47
48 import javax.swing.*;
49 import javax.swing.event.DocumentEvent;
50 import java.awt.*;
51 import java.io.File;
52 import java.util.List;
53
54 public class MoveFilesOrDirectoriesDialog extends DialogWrapper{
55   @NonNls private static final String RECENT_KEYS = "MoveFile.RECENT_KEYS";
56
57   public interface Callback {
58     void run(MoveFilesOrDirectoriesDialog dialog);
59   }
60
61   private JLabel myNameLabel;
62   private TextFieldWithHistoryWithBrowseButton myTargetDirectoryField;
63   private String myHelpID;
64   private final Project myProject;
65   private final Callback myCallback;
66   private PsiDirectory myTargetDirectory;
67   private JCheckBox myCbSearchForReferences;
68
69   public MoveFilesOrDirectoriesDialog(Project project, Callback callback) {
70     super(project, true);
71     myProject = project;
72     myCallback = callback;
73     setTitle(RefactoringBundle.message("move.title"));
74     init();
75   }
76
77   protected Action[] createActions(){
78     return new Action[]{getOKAction(),getCancelAction(),getHelpAction()};
79   }
80
81   public JComponent getPreferredFocusedComponent() {
82     return myTargetDirectoryField.getChildComponent();
83   }
84
85   protected JComponent createCenterPanel() {
86     return null;
87   }
88
89   protected JComponent createNorthPanel() {
90     JPanel panel = new JPanel(new GridBagLayout());
91     final GridBagConstraints c = new GridBagConstraints();
92     c.gridx = 0;
93     c.gridy = 0;
94     c.fill = GridBagConstraints.HORIZONTAL;
95     c.insets = new Insets(0, 2, 0, 0);
96
97     myNameLabel = new JLabel();
98     panel.add(myNameLabel, c);
99     c.insets.top = 10;
100     c.gridy++;    
101     panel.add(new JLabel(RefactoringBundle.message("move.files.to.directory.label")), c);
102     c.insets.top = 0;
103     
104     myTargetDirectoryField = new TextFieldWithHistoryWithBrowseButton();
105     final List<String> recentEntries = RecentsManager.getInstance(myProject).getRecentEntries(RECENT_KEYS);
106     if (recentEntries != null) {
107       myTargetDirectoryField.getChildComponent().setHistory(recentEntries);
108     }
109     final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
110     myTargetDirectoryField.addBrowseFolderListener(RefactoringBundle.message("select.target.directory"),
111                                                    RefactoringBundle.message("the.file.will.be.moved.to.this.directory"),
112                                                    myProject,
113                                                    descriptor,
114                                                    TextComponentAccessor.TEXT_FIELD_WITH_HISTORY_WHOLE_TEXT);
115     final JTextField textField = myTargetDirectoryField.getChildComponent().getTextEditor();
116     FileChooserFactory.getInstance().installFileCompletion(textField, descriptor, true, getDisposable());
117     myTargetDirectoryField.setTextFieldPreferredWidth(60);
118     c.insets.left = 0;
119     c.gridy++;
120     panel.add(myTargetDirectoryField, c);
121     String shortcutText = KeymapUtil.getFirstKeyboardShortcutText(ActionManager.getInstance().getAction(IdeActions.ACTION_CODE_COMPLETION));
122     final JLabel label = new JLabel(RefactoringBundle.message("path.completion.shortcut", shortcutText));
123     UIUtil.applyStyle(UIUtil.ComponentStyle.MINI, label);
124     c.insets.left = 6;
125     c.gridy++;
126     panel.add(label, c);
127
128     myCbSearchForReferences = new NonFocusableCheckBox(RefactoringBundle.message("search.for.references"));
129     myCbSearchForReferences.setSelected(RefactoringSettings.getInstance().MOVE_SEARCH_FOR_REFERENCES_FOR_FILE);
130     c.insets.top = 10;
131     c.insets.left = 0;
132     c.gridy++;
133     panel.add(myCbSearchForReferences, c);
134
135     textField.getDocument().addDocumentListener(new DocumentAdapter() {
136       @Override
137       protected void textChanged(DocumentEvent e) {
138         validateOKButton();
139       }
140     });
141     Disposer.register(getDisposable(), myTargetDirectoryField);
142
143     return panel;
144   }
145
146   public void setData(PsiElement[] psiElements, PsiDirectory initialTargetDirectory, @NonNls String helpID) {
147     if (psiElements.length == 1) {
148       String text;
149       if (psiElements[0] instanceof PsiFile) {
150         text = RefactoringBundle.message("move.file.0",
151                                          ((PsiFile)psiElements[0]).getVirtualFile().getPresentableUrl());
152       }
153       else {
154         text = RefactoringBundle.message("move.directory.0",
155                                          ((PsiDirectory)psiElements[0]).getVirtualFile().getPresentableUrl());
156       }
157       myNameLabel.setText(text);
158     }
159     else {
160       boolean isFile = true;
161       boolean isDirectory = true;
162       for (PsiElement psiElement : psiElements) {
163         isFile &= psiElement instanceof PsiFile;
164         isDirectory &= psiElement instanceof PsiDirectory;
165       }
166       myNameLabel.setText(isFile ?
167                           RefactoringBundle.message("move.specified.files") :
168                           isDirectory ?
169                           RefactoringBundle.message("move.specified.directories") :
170                           RefactoringBundle.message("move.specified.elements"));
171     }
172
173     myTargetDirectoryField.getChildComponent().setText(initialTargetDirectory == null ? "" : initialTargetDirectory.getVirtualFile().getPresentableUrl());
174
175     validateOKButton();
176     myHelpID = helpID;
177   }
178
179   protected void doHelpAction() {
180     HelpManager.getInstance().invokeHelp(myHelpID);
181   }
182
183   private void validateOKButton() {
184     setOKActionEnabled(myTargetDirectoryField.getChildComponent().getText().length() > 0);
185   }
186
187   protected void doOKAction() {
188     //myTargetDirectoryField.getChildComponent().addCurrentTextToHistory();
189     RecentsManager.getInstance(myProject).registerRecentEntry(RECENT_KEYS, myTargetDirectoryField.getChildComponent().getText());
190     RefactoringSettings.getInstance().MOVE_SEARCH_FOR_REFERENCES_FOR_FILE = myCbSearchForReferences.isSelected();
191     CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
192       public void run() {
193         final Runnable action = new Runnable() {
194           public void run() {
195             String directoryName = myTargetDirectoryField.getChildComponent().getText().replace(File.separatorChar, '/');
196             try {
197               myTargetDirectory = DirectoryUtil.mkdirs(PsiManager.getInstance(myProject), directoryName);
198             }
199             catch (IncorrectOperationException e) {
200               // ignore
201             }
202           }
203         };
204
205         ApplicationManager.getApplication().runWriteAction(action);
206         if (myTargetDirectory == null) {
207           CommonRefactoringUtil.showErrorMessage(getTitle(),
208                                                  RefactoringBundle.message("cannot.create.directory"), myHelpID, myProject);
209           return;
210         }
211         myCallback.run(MoveFilesOrDirectoriesDialog.this);
212       }
213     }, RefactoringBundle.message("move.title"), null);
214   }
215
216   public PsiDirectory getTargetDirectory() {
217     return myTargetDirectory;
218   }
219 }