combobox with browse button with path completion; recent manager to be used (IDEA...
[idea/community.git] / platform / lang-impl / src / com / intellij / refactoring / copy / CopyFilesOrDirectoriesDialog.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.copy;
18
19 import com.intellij.ide.util.DirectoryUtil;
20 import com.intellij.openapi.application.ApplicationManager;
21 import com.intellij.openapi.command.CommandProcessor;
22 import com.intellij.openapi.fileChooser.FileChooserDescriptor;
23 import com.intellij.openapi.fileChooser.FileChooserDescriptorFactory;
24 import com.intellij.openapi.help.HelpManager;
25 import com.intellij.openapi.project.Project;
26 import com.intellij.openapi.ui.DialogWrapper;
27 import com.intellij.openapi.ui.Messages;
28 import com.intellij.openapi.ui.TextComponentAccessor;
29 import com.intellij.openapi.ui.impl.DialogWrapperPeerImpl;
30 import com.intellij.psi.PsiDirectory;
31 import com.intellij.psi.PsiElement;
32 import com.intellij.psi.PsiFile;
33 import com.intellij.psi.PsiManager;
34 import com.intellij.refactoring.RefactoringBundle;
35 import com.intellij.ui.DocumentAdapter;
36 import com.intellij.ui.RecentsManager;
37 import com.intellij.ui.TextFieldWithHistoryWithBrowseButton;
38 import com.intellij.util.IncorrectOperationException;
39 import org.jetbrains.annotations.NonNls;
40
41 import javax.swing.*;
42 import javax.swing.event.DocumentEvent;
43 import javax.swing.event.DocumentListener;
44 import java.awt.*;
45 import java.io.File;
46 import java.util.List;
47
48 class CopyFilesOrDirectoriesDialog extends DialogWrapper{
49   private JLabel myInformationLabel;
50   private TextFieldWithHistoryWithBrowseButton myTargetDirectoryField;
51   private JTextField myNewNameField;
52   private final Project myProject;
53   private final boolean myShowDirectoryField;
54   private final boolean myShowNewNameField;
55
56   private PsiDirectory myTargetDirectory;
57   @NonNls private static final String RECENT_KEYS = "CopyFile.RECENT_KEYS";
58
59   public CopyFilesOrDirectoriesDialog(PsiElement[] elements, PsiDirectory defaultTargetDirectory, Project project, boolean doClone) {
60     super(project, true);
61     myProject = project;
62     myShowDirectoryField = !doClone;
63     myShowNewNameField = elements.length == 1;
64
65     if (doClone && elements.length != 1) {
66       throw new IllegalArgumentException("wrong number of elements to clone: " + elements.length);
67     }
68
69     setTitle(doClone ?
70              RefactoringBundle.message("copy.files.clone.title") :
71              RefactoringBundle.message("copy.files.copy.title"));
72     init();
73
74     if (elements.length == 1) {
75       String text;
76       if (elements[0] instanceof PsiFile) {
77         PsiFile file = (PsiFile)elements[0];
78         text = doClone ?
79                RefactoringBundle.message("copy.files.clone.file.0", file.getVirtualFile().getPresentableUrl()) :
80                RefactoringBundle.message("copy.files.copy.file.0", file.getVirtualFile().getPresentableUrl());
81         final String fileName = file.getName();
82         myNewNameField.setText(fileName);
83         final int dotIdx = fileName.lastIndexOf(".");
84         if (dotIdx > -1) {
85           myNewNameField.select(0, dotIdx);
86           myNewNameField.putClientProperty(DialogWrapperPeerImpl.HAVE_INITIAL_SELECTION, true);
87         }
88       }
89       else {
90         PsiDirectory directory = (PsiDirectory)elements[0];
91         text = doClone ?
92                RefactoringBundle.message("copy.files.clone.directory.0", directory.getVirtualFile().getPresentableUrl()) :
93                RefactoringBundle.message("copy.files.copy.directory.0", directory.getVirtualFile().getPresentableUrl());
94         myNewNameField.setText(directory.getName());
95       }
96       myInformationLabel.setText(text);
97     }
98     else {
99       setMultipleElementCopyLabel(elements);
100     }
101
102     if (myShowDirectoryField) {
103       myTargetDirectoryField.getChildComponent().setText(defaultTargetDirectory == null ? "" : defaultTargetDirectory.getVirtualFile().getPresentableUrl());
104     }
105     validateOKButton();
106   }
107
108   private void setMultipleElementCopyLabel(PsiElement[] elements) {
109     boolean allFiles = true;
110     boolean allDirectories = true;
111     for (PsiElement element : elements) {
112       if (element instanceof PsiDirectory) {
113         allFiles = false;
114       }
115       else {
116         allDirectories = false;
117       }
118     }
119     if (allFiles) {
120       myInformationLabel.setText(RefactoringBundle.message("copy.files.copy.specified.files.label"));
121     }
122     else if (allDirectories) {
123       myInformationLabel.setText(RefactoringBundle.message("copy.files.copy.specified.directories.label"));
124     }
125     else {
126       myInformationLabel.setText(RefactoringBundle.message("copy.files.copy.specified.mixed.label"));
127     }
128   }
129
130   protected Action[] createActions(){
131     return new Action[]{getOKAction(),getCancelAction(),getHelpAction()};
132   }
133
134   public JComponent getPreferredFocusedComponent() {
135     return myShowNewNameField ? myNewNameField : myTargetDirectoryField.getChildComponent();
136   }
137
138   protected JComponent createCenterPanel() {
139     return new JPanel(new BorderLayout());
140   }
141
142   protected JComponent createNorthPanel() {
143     JPanel panel = new JPanel(new GridBagLayout());
144
145     myInformationLabel = new JLabel();
146
147     panel.add(myInformationLabel, new GridBagConstraints(0,0,2,1,1,0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(4,8,4,8),0,0));
148
149     DocumentListener documentListener = new DocumentAdapter() {
150       public void textChanged(DocumentEvent event) {
151         validateOKButton();
152       }
153     };
154     if (myShowNewNameField) {
155       myNewNameField = new JTextField();
156       Dimension size = myNewNameField.getPreferredSize();
157       FontMetrics fontMetrics = myNewNameField.getFontMetrics(myNewNameField.getFont());
158       size.width = fontMetrics.charWidth('a') * 60;
159       myNewNameField.setPreferredSize(size);
160
161       panel.add(new JLabel(RefactoringBundle.message("copy.files.new.name.label")), new GridBagConstraints(0,1,1,1,0,0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(4,8,4,8),0,0));
162
163       panel.add(myNewNameField, new GridBagConstraints(1,1,1,1,1,0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(4,0,4,8),0,0));
164
165       myNewNameField.getDocument().addDocumentListener(documentListener);
166     }
167
168     if (myShowDirectoryField) {
169       panel.add(new JLabel(RefactoringBundle.message("copy.files.to.directory.label")), new GridBagConstraints(0,2,1,1,0,0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(4,8,4,8),0,0));
170
171       myTargetDirectoryField = new TextFieldWithHistoryWithBrowseButton();
172       final List<String> recentEntries = RecentsManager.getInstance(myProject).getRecentEntries(RECENT_KEYS);
173       
174       if (recentEntries != null) {
175         myTargetDirectoryField.getChildComponent().setHistory(recentEntries);
176       }
177       final FileChooserDescriptor descriptor = FileChooserDescriptorFactory.createSingleFolderDescriptor();
178       myTargetDirectoryField.addBrowseFolderListener(RefactoringBundle.message("select.target.directory"),
179                                                                             RefactoringBundle.message("the.file.will.be.copied.to.this.directory"),
180                                                                             myProject, descriptor,
181                                                                             TextComponentAccessor.TEXT_FIELD_WITH_HISTORY_WHOLE_TEXT);
182       
183       myTargetDirectoryField.setTextFieldPreferredWidth(60);
184       panel.add(myTargetDirectoryField, new GridBagConstraints(1,2,1,1,1,0,GridBagConstraints.WEST,GridBagConstraints.HORIZONTAL,new Insets(4,0,4,8),0,0));
185
186       myTargetDirectoryField.getChildComponent().addDocumentListener(new DocumentAdapter() {
187         @Override
188         protected void textChanged(DocumentEvent e) {
189           validateOKButton();
190         }
191       });
192     }
193
194     return panel;
195   }
196
197   public PsiDirectory getTargetDirectory() {
198     return myTargetDirectory;
199   }
200
201   public String getNewName() {
202     return myNewNameField != null ? myNewNameField.getText().trim() : null;
203   }
204
205   protected void doOKAction(){
206     if (myShowNewNameField) {
207       String newName = getNewName();
208
209       if (newName.length() == 0) {
210         Messages.showMessageDialog(myProject, RefactoringBundle.message("no.new.name.specified"), RefactoringBundle.message("error.title"), Messages.getErrorIcon());
211         return;
212       }
213     }
214
215     if (myShowDirectoryField) {
216       final String targetDirectoryName = myTargetDirectoryField.getChildComponent().getText();
217
218       if (targetDirectoryName.length() == 0) {
219         Messages.showMessageDialog(myProject, RefactoringBundle.message("no.target.directory.specified"), RefactoringBundle.message("error.title"), Messages.getErrorIcon());
220         return;
221       }
222
223       RecentsManager.getInstance(myProject).registerRecentEntry(RECENT_KEYS, targetDirectoryName);
224
225       CommandProcessor.getInstance().executeCommand(myProject, new Runnable() {
226         public void run() {
227           ApplicationManager.getApplication().runWriteAction(new Runnable() {
228             public void run() {
229               try {
230                 myTargetDirectory = DirectoryUtil.mkdirs(PsiManager.getInstance(myProject), targetDirectoryName.replace(File.separatorChar, '/'));
231               }
232               catch (IncorrectOperationException e) {
233               }
234             }
235           });
236         }
237       }, RefactoringBundle.message("create.directory"), null);
238
239       if (myTargetDirectory == null) {
240         Messages.showMessageDialog(myProject, RefactoringBundle.message("cannot.create.directory"), RefactoringBundle.message("error.title"), Messages.getErrorIcon());
241         return;
242       }
243     }
244
245     super.doOKAction();
246   }
247
248   private void validateOKButton() {
249     if (myShowDirectoryField) {
250       if (myTargetDirectoryField.getChildComponent().getText().length() == 0) {
251         setOKActionEnabled(false);
252         return;
253       }
254     }
255     if (myShowNewNameField) {
256       if (getNewName().length() == 0) {
257         setOKActionEnabled(false);
258         return;
259       }
260     }
261     setOKActionEnabled(true);
262   }
263
264   protected void doHelpAction() {
265     HelpManager.getInstance().invokeHelp("refactoring.copyClass");
266   }
267 }