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.
17 package com
.intellij
.ide
.util
;
19 import com
.intellij
.ide
.IdeBundle
;
20 import com
.intellij
.ide
.projectView
.BaseProjectTreeBuilder
;
21 import com
.intellij
.ide
.projectView
.ProjectViewNode
;
22 import com
.intellij
.ide
.projectView
.TreeStructureProvider
;
23 import com
.intellij
.ide
.projectView
.impl
.AbstractProjectTreeStructure
;
24 import com
.intellij
.ide
.projectView
.impl
.ProjectAbstractTreeStructureBase
;
25 import com
.intellij
.ide
.projectView
.impl
.ProjectTreeBuilder
;
26 import com
.intellij
.ide
.projectView
.impl
.nodes
.PsiFileNode
;
27 import com
.intellij
.ide
.util
.gotoByName
.ChooseByNameModel
;
28 import com
.intellij
.ide
.util
.gotoByName
.ChooseByNamePanel
;
29 import com
.intellij
.ide
.util
.gotoByName
.ChooseByNamePopupComponent
;
30 import com
.intellij
.ide
.util
.gotoByName
.GotoFileCellRenderer
;
31 import com
.intellij
.ide
.util
.treeView
.AlphaComparator
;
32 import com
.intellij
.ide
.util
.treeView
.NodeRenderer
;
33 import com
.intellij
.openapi
.application
.ApplicationManager
;
34 import com
.intellij
.openapi
.application
.ModalityState
;
35 import com
.intellij
.openapi
.fileTypes
.FileType
;
36 import com
.intellij
.openapi
.fileTypes
.FileTypeManager
;
37 import com
.intellij
.openapi
.project
.Project
;
38 import com
.intellij
.openapi
.ui
.DialogWrapper
;
39 import com
.intellij
.openapi
.util
.Condition
;
40 import com
.intellij
.openapi
.util
.Disposer
;
41 import com
.intellij
.openapi
.vfs
.VirtualFile
;
42 import com
.intellij
.openapi
.wm
.ex
.WindowManagerEx
;
43 import com
.intellij
.psi
.PsiElement
;
44 import com
.intellij
.psi
.PsiFile
;
45 import com
.intellij
.psi
.PsiManager
;
46 import com
.intellij
.psi
.search
.FilenameIndex
;
47 import com
.intellij
.psi
.search
.GlobalSearchScope
;
48 import com
.intellij
.ui
.TabbedPaneWrapper
;
49 import com
.intellij
.ui
.TreeSpeedSearch
;
50 import com
.intellij
.ui
.treeStructure
.Tree
;
51 import com
.intellij
.util
.ArrayUtil
;
52 import com
.intellij
.util
.ui
.UIUtil
;
53 import gnu
.trove
.THashSet
;
54 import org
.jetbrains
.annotations
.NotNull
;
55 import org
.jetbrains
.annotations
.Nullable
;
58 import javax
.swing
.event
.ChangeEvent
;
59 import javax
.swing
.event
.ChangeListener
;
60 import javax
.swing
.event
.TreeSelectionEvent
;
61 import javax
.swing
.event
.TreeSelectionListener
;
62 import javax
.swing
.tree
.DefaultMutableTreeNode
;
63 import javax
.swing
.tree
.DefaultTreeModel
;
64 import javax
.swing
.tree
.TreePath
;
65 import javax
.swing
.tree
.TreeSelectionModel
;
67 import java
.awt
.event
.KeyAdapter
;
68 import java
.awt
.event
.KeyEvent
;
69 import java
.awt
.event
.MouseAdapter
;
70 import java
.awt
.event
.MouseEvent
;
71 import java
.util
.ArrayList
;
72 import java
.util
.Arrays
;
73 import java
.util
.List
;
77 * @author Anton Katilin
78 * @author Vladimir Kondratyev
80 public final class TreeFileChooserDialog
extends DialogWrapper
implements TreeFileChooser
{
82 private PsiFile mySelectedFile
= null;
83 private final Project myProject
;
84 private BaseProjectTreeBuilder myBuilder
;
85 private TabbedPaneWrapper myTabbedPane
;
86 private ChooseByNamePanel myGotoByNamePanel
;
87 @Nullable private final PsiFile myInitialFile
;
88 @Nullable private final PsiFileFilter myFilter
;
89 @Nullable private final FileType myFileType
;
91 private final boolean myDisableStructureProviders
;
92 private final boolean myShowLibraryContents
;
94 public TreeFileChooserDialog(final Project project
,
96 @Nullable final PsiFile initialFile
,
97 @Nullable FileType fileType
,
98 @Nullable PsiFileFilter filter
,
99 final boolean disableStructureProviders
,
100 final boolean showLibraryContents
) {
101 super(project
, true);
102 myInitialFile
= initialFile
;
104 myFileType
= fileType
;
105 myDisableStructureProviders
= disableStructureProviders
;
106 myShowLibraryContents
= showLibraryContents
;
110 if (initialFile
!= null) {
111 // dialog does not exist yet
112 SwingUtilities
.invokeLater(new Runnable(){
114 selectFile(initialFile
);
119 SwingUtilities
.invokeLater(new Runnable(){
121 handleSelectionChanged();
126 protected JComponent
createCenterPanel() {
127 final DefaultTreeModel model
= new DefaultTreeModel(new DefaultMutableTreeNode());
128 myTree
= new Tree(model
);
130 final ProjectAbstractTreeStructureBase treeStructure
= new AbstractProjectTreeStructure(myProject
) {
131 public boolean isFlattenPackages() {
135 public boolean isShowMembers() {
139 public boolean isHideEmptyMiddlePackages() {
143 public Object
[] getChildElements(final Object element
) {
144 return filterFiles(super.getChildElements(element
));
147 public boolean isAbbreviatePackageNames() {
151 public boolean isShowLibraryContents() {
152 return myShowLibraryContents
;
155 public boolean isShowModules() {
159 public List
<TreeStructureProvider
> getProviders() {
160 return myDisableStructureProviders ?
null : super.getProviders();
163 myBuilder
= new ProjectTreeBuilder(myProject
, myTree
, model
, AlphaComparator
.INSTANCE
, treeStructure
);
165 myTree
.setRootVisible(false);
167 myTree
.getSelectionModel().setSelectionMode(TreeSelectionModel
.SINGLE_TREE_SELECTION
);
168 myTree
.setCellRenderer(new NodeRenderer());
169 UIUtil
.setLineStyleAngled(myTree
);
171 final JScrollPane scrollPane
= new JScrollPane(myTree
);
172 scrollPane
.setPreferredSize(new Dimension(500, 300));
174 myTree
.addKeyListener(new KeyAdapter() {
175 public void keyPressed(final KeyEvent e
) {
176 if (KeyEvent
.VK_ENTER
== e
.getKeyCode()) {
182 myTree
.addMouseListener(new MouseAdapter() {
183 public void mouseClicked(final MouseEvent e
) {
184 if (e
.getClickCount() == 2) {
185 final TreePath path
= myTree
.getPathForLocation(e
.getX(), e
.getY());
186 if (path
!= null && myTree
.isPathSelected(path
)) {
193 myTree
.addTreeSelectionListener(
194 new TreeSelectionListener() {
195 public void valueChanged(final TreeSelectionEvent e
) {
196 handleSelectionChanged();
201 new TreeSpeedSearch(myTree
);
203 myTabbedPane
= new TabbedPaneWrapper(getDisposable());
205 final JPanel dummyPanel
= new JPanel(new BorderLayout());
207 if (myInitialFile
!= null) {
208 name
= myInitialFile
.getName();
210 PsiElement context
= myInitialFile
== null ?
null : myInitialFile
;
211 myGotoByNamePanel
= new ChooseByNamePanel(myProject
, new MyGotoFileModel(), name
, true, context
) {
212 protected void close(final boolean isOk
) {
223 protected void initUI(final ChooseByNamePopupComponent
.Callback callback
,
224 final ModalityState modalityState
,
225 boolean allowMultipleSelection
) {
226 super.initUI(callback
, modalityState
, allowMultipleSelection
);
227 dummyPanel
.add(myGotoByNamePanel
.getPanel(), BorderLayout
.CENTER
);
228 //IdeFocusTraversalPolicy.getPreferredFocusedComponent(myGotoByNamePanel.getPanel()).requestFocus();
231 protected void choosenElementMightChange() {
232 handleSelectionChanged();
236 myTabbedPane
.addTab(IdeBundle
.message("tab.chooser.project"), scrollPane
);
237 myTabbedPane
.addTab(IdeBundle
.message("tab.chooser.search.by.name"), dummyPanel
);
239 SwingUtilities
.invokeLater(new Runnable() {
241 myGotoByNamePanel
.invoke(new MyCallback(), ModalityState
.stateForComponent(getRootPane()), false);
245 myTabbedPane
.addChangeListener(
246 new ChangeListener() {
247 public void stateChanged(final ChangeEvent e
) {
248 handleSelectionChanged();
253 return myTabbedPane
.getComponent();
256 private void handleSelectionChanged(){
257 final PsiFile selection
= calcSelectedClass();
258 setOKActionEnabled(selection
!= null);
261 protected void doOKAction() {
262 mySelectedFile
= calcSelectedClass();
263 if (mySelectedFile
== null) return;
267 public void doCancelAction() {
268 mySelectedFile
= null;
269 super.doCancelAction();
272 public PsiFile
getSelectedFile(){
273 return mySelectedFile
;
276 public void selectFile(@NotNull final PsiFile file
) {
277 // Select element in the tree
278 ApplicationManager
.getApplication().invokeLater(new Runnable() {
280 if (myBuilder
!= null) {
281 myBuilder
.select(file
, file
.getVirtualFile(), true);
284 }, ModalityState
.stateForComponent(getWindow()));
287 public void showDialog() {
291 private PsiFile
calcSelectedClass() {
292 if (myTabbedPane
.getSelectedIndex() == 1) {
293 return (PsiFile
)myGotoByNamePanel
.getChosenElement();
296 final TreePath path
= myTree
.getSelectionPath();
297 if (path
== null) return null;
298 final DefaultMutableTreeNode node
= (DefaultMutableTreeNode
)path
.getLastPathComponent();
299 final Object userObject
= node
.getUserObject();
300 if (!(userObject
instanceof ProjectViewNode
)) return null;
301 ProjectViewNode pvNode
= (ProjectViewNode
) userObject
;
302 VirtualFile vFile
= pvNode
.getVirtualFile();
303 if (vFile
!= null && !vFile
.isDirectory()) {
304 return PsiManager
.getInstance(myProject
).findFile(vFile
);
312 public void dispose() {
313 if (myBuilder
!= null) {
314 Disposer
.dispose(myBuilder
);
320 protected String
getDimensionServiceKey() {
321 return "#com.intellij.ide.util.TreeFileChooserDialog";
324 public JComponent
getPreferredFocusedComponent() {
328 private final class MyGotoFileModel
implements ChooseByNameModel
{
329 private final int myMaxSize
= WindowManagerEx
.getInstanceEx().getFrame(myProject
).getSize().width
;
330 public Object
[] getElementsByName(final String name
, final boolean checkBoxState
, final String pattern
) {
331 final PsiFile
[] psiFiles
= FilenameIndex
.getFilesByName(myProject
, name
, GlobalSearchScope
.projectScope(myProject
));
332 return filterFiles(psiFiles
);
335 public String
getPromptText() {
336 return IdeBundle
.message("prompt.filechooser.enter.file.name");
339 public String
getCheckBoxName() {
343 public char getCheckBoxMnemonic() {
347 public String
getNotInMessage() {
351 public String
getNotFoundMessage() {
355 public boolean loadInitialCheckBoxState() {
359 public void saveInitialCheckBoxState(final boolean state
) {
362 public PsiElementListCellRenderer
getListCellRenderer() {
363 return new GotoFileCellRenderer(myMaxSize
);
366 public String
[] getNames(final boolean checkBoxState
) {
367 final String
[] fileNames
= FilenameIndex
.getAllFilenames(myProject
);
369 final Set
<String
> array
= new THashSet
<String
>();
370 FileTypeManager fileTypeManager
= FileTypeManager
.getInstance();
371 for (String fileName
: fileNames
) {
373 if (myFileType
!= null && fileTypeManager
.getFileTypeByFileName(fileName
) != myFileType
) {
377 if (!array
.contains(fileName
)) {
382 final String
[] result
= ArrayUtil
.toStringArray(array
);
387 public String
getElementName(final Object element
) {
388 if (!(element
instanceof PsiFile
)) return null;
389 return ((PsiFile
)element
).getName();
393 public String
getFullName(final Object element
) {
394 if (element
instanceof PsiFile
) {
395 final VirtualFile virtualFile
= ((PsiFile
)element
).getVirtualFile();
396 return virtualFile
!= null ? virtualFile
.getPath() : null;
399 return getElementName(element
);
402 public String
getHelpId() {
407 public String
[] getSeparators() {
408 return new String
[] {"/", "\\"};
412 private final class MyCallback
extends ChooseByNamePopupComponent
.Callback
{
413 public void elementChosen(final Object element
) {
414 mySelectedFile
= (PsiFile
)element
;
419 private Object
[] filterFiles(final Object
[] list
) {
420 Condition
<PsiFile
> condition
= new Condition
<PsiFile
>() {
421 public boolean value(final PsiFile psiFile
) {
422 if (myFilter
!= null && !myFilter
.accept(psiFile
)) {
425 return myFileType
== null || psiFile
.getFileType() == myFileType
;
428 final List
<Object
> result
= new ArrayList
<Object
>(list
.length
);
429 for (Object o
: list
) {
430 final PsiFile psiFile
;
431 if (o
instanceof PsiFile
) {
432 psiFile
= (PsiFile
)o
;
434 else if (o
instanceof PsiFileNode
) {
435 psiFile
= ((PsiFileNode
)o
).getValue();
440 if (psiFile
!= null && !condition
.value(psiFile
)) {
444 if (o
instanceof ProjectViewNode
) {
445 final ProjectViewNode projectViewNode
= (ProjectViewNode
)o
;
446 if (!projectViewNode
.canHaveChildrenMatching(condition
)) {
453 return ArrayUtil
.toObjectArray(result
);