inner classes handling
[fedora-idea.git] / platform / lang-impl / src / com / intellij / internal / psiView / PsiViewerDialog.java
blobff785b0c563bd2c3e3e346bd578162105319a2d6
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.
17 /**
18 * class PsiViewerDialog
19 * created Aug 25, 2001
20 * @author Jeka
22 package com.intellij.internal.psiView;
24 import com.intellij.lang.ASTNode;
25 import com.intellij.lang.Language;
26 import com.intellij.lang.LanguageUtil;
27 import com.intellij.openapi.editor.Document;
28 import com.intellij.openapi.editor.Editor;
29 import com.intellij.openapi.editor.EditorFactory;
30 import com.intellij.openapi.editor.markup.HighlighterLayer;
31 import com.intellij.openapi.editor.markup.HighlighterTargetArea;
32 import com.intellij.openapi.editor.markup.RangeHighlighter;
33 import com.intellij.openapi.editor.markup.TextAttributes;
34 import com.intellij.openapi.extensions.Extensions;
35 import com.intellij.openapi.fileTypes.*;
36 import com.intellij.openapi.fileTypes.impl.AbstractFileType;
37 import com.intellij.openapi.project.Project;
38 import com.intellij.openapi.ui.DialogWrapper;
39 import com.intellij.openapi.ui.Messages;
40 import com.intellij.openapi.util.Disposer;
41 import com.intellij.openapi.util.TextRange;
42 import com.intellij.psi.PsiElement;
43 import com.intellij.psi.PsiFile;
44 import com.intellij.psi.PsiFileFactory;
45 import com.intellij.psi.PsiReference;
46 import com.intellij.psi.search.FilenameIndex;
47 import com.intellij.psi.search.GlobalSearchScope;
48 import com.intellij.ui.SortedComboBoxModel;
49 import com.intellij.ui.TreeSpeedSearch;
50 import com.intellij.ui.treeStructure.Tree;
51 import com.intellij.util.IncorrectOperationException;
52 import com.intellij.util.ui.UIUtil;
53 import com.intellij.util.ui.tree.TreeUtil;
55 import javax.swing.*;
56 import javax.swing.event.TreeSelectionEvent;
57 import javax.swing.event.TreeSelectionListener;
58 import javax.swing.tree.DefaultMutableTreeNode;
59 import javax.swing.tree.DefaultTreeModel;
60 import javax.swing.tree.TreePath;
61 import java.awt.*;
62 import java.awt.event.*;
63 import java.util.*;
64 import java.util.List;
66 public class PsiViewerDialog extends DialogWrapper {
67 private static final Object EXTENSION_KEY = new Object();
69 private final Project myProject;
71 private final Tree myTree;
72 private final ViewerTreeBuilder myTreeBuilder;
74 private final JList myRefs;
76 private Editor myEditor;
77 private String myLastParsedText = null;
79 private List<JRadioButton> myExtensionButtons = new ArrayList<JRadioButton>();
80 private JRadioButton[] myFileTypeButtons;
81 private FileType[] myFileTypes;
83 private JCheckBox myShowWhiteSpacesBox;
84 private JPanel myStructureTreePanel;
85 private JPanel myTextPanel;
86 private JPanel myPanel;
87 private JPanel myChoicesPanel;
88 private JCheckBox myShowTreeNodesCheckBox;
89 private JComboBox myDialectsComboBox;
90 private JPanel myReferencesPanel;
92 public PsiViewerDialog(Project project,boolean modal) {
93 super(project, true);
94 setTitle("PSI Viewer");
95 myProject = project;
96 myTree = new Tree(new DefaultTreeModel(new DefaultMutableTreeNode()));
97 UIUtil.setLineStyleAngled(myTree);
98 myTree.setRootVisible(false);
99 myTree.setShowsRootHandles(true);
100 myTree.updateUI();
101 ToolTipManager.sharedInstance().registerComponent(myTree);
102 TreeUtil.installActions(myTree);
103 new TreeSpeedSearch(myTree);
104 myTreeBuilder = new ViewerTreeBuilder(project, myTree);
106 myTree.addTreeSelectionListener(new MyTreeSelectionListener());
108 JScrollPane scrollPane = new JScrollPane(myTree);
109 JPanel panel = new JPanel(new BorderLayout());
110 panel.add(scrollPane, BorderLayout.CENTER);
111 myStructureTreePanel.setLayout(new BorderLayout());
112 myStructureTreePanel.add(panel, BorderLayout.CENTER);
114 myRefs = new JList(new DefaultListModel());
115 JScrollPane refScrollPane = new JScrollPane(myRefs);
116 JPanel refPanel = new JPanel(new BorderLayout());
117 refPanel.add(refScrollPane, BorderLayout.CENTER);
118 myReferencesPanel.setLayout(new BorderLayout());
119 myReferencesPanel.add(refPanel, BorderLayout.CENTER);
120 final GoToListener listener = new GoToListener(myRefs, project);
121 myRefs.addKeyListener(listener);
122 myRefs.addMouseListener(listener);
124 setModal(modal);
125 setOKButtonText("&Build PSI Tree");
126 init();
129 protected String getDimensionServiceKey(){
130 return "#com.intellij.internal.psiView.PsiViewerDialog";
133 public JComponent getPreferredFocusedComponent() {
134 return myEditor.getContentComponent();
137 protected void init() {
138 EditorFactory editorFactory = EditorFactory.getInstance();
139 Document document = editorFactory.createDocument("");
140 myEditor = editorFactory.createEditor(document, myProject);
141 myEditor.getSettings().setFoldingOutlineShown(false);
143 for(PsiViewerExtension extension: Extensions.getExtensions(PsiViewerExtension.EP_NAME)) {
144 JRadioButton button = new JRadioButton(extension.getName());
145 button.putClientProperty(EXTENSION_KEY, extension);
146 myExtensionButtons.add(button);
150 FileType[] fileTypes = FileTypeManager.getInstance().getRegisteredFileTypes();
151 Arrays.sort(fileTypes,new Comparator<FileType>() {
152 public int compare(final FileType o1, final FileType o2) {
153 return o1.getName().compareTo(o2.getName());
157 List<FileType> customFileTypes = new ArrayList<FileType>();
159 for (FileType fileType : fileTypes) {
160 if (fileType != StdFileTypes.GUI_DESIGNER_FORM && fileType != StdFileTypes.IDEA_MODULE && fileType != StdFileTypes.IDEA_PROJECT &&
161 fileType != StdFileTypes.IDEA_WORKSPACE && fileType != FileTypes.ARCHIVE && fileType != FileTypes.UNKNOWN &&
162 fileType != FileTypes.PLAIN_TEXT && !(fileType instanceof AbstractFileType) && !fileType.isBinary() && !fileType.isReadOnly()) {
163 customFileTypes.add(fileType);
167 myFileTypes = customFileTypes.toArray(new FileType[customFileTypes.size()]);
168 myFileTypeButtons = new JRadioButton[myFileTypes.length];
170 ButtonGroup bg = new ButtonGroup();
171 for (JRadioButton button : myExtensionButtons) {
172 bg.add(button);
175 final int rows = 1 + myFileTypes.length / 7;
176 JPanel choicesBox = new JPanel(new GridLayout(rows, 7));
178 for (JRadioButton extensionButton : myExtensionButtons) {
179 choicesBox.add(extensionButton);
182 for (int i = 0; i < myFileTypes.length; i++) {
183 FileType fileType = myFileTypes[i];
184 JRadioButton button = new JRadioButton(fileType.getName()+" file");
185 bg.add(button);
186 choicesBox.add(button);
187 myFileTypeButtons[i] = button;
190 final ActionListener updateDialectsListener = new ActionListener() {
191 public void actionPerformed(final ActionEvent e) {
192 updateDialectsCombo();
195 final Enumeration<AbstractButton> buttonEnum = bg.getElements();
196 while (buttonEnum.hasMoreElements()) {
197 buttonEnum.nextElement().addActionListener(updateDialectsListener);
199 updateDialectsCombo();
200 myDialectsComboBox.setRenderer(new DefaultListCellRenderer() {
201 @Override
202 public Component getListCellRendererComponent(final JList list,
203 final Object value,
204 final int index,
205 final boolean isSelected,
206 final boolean cellHasFocus) {
207 final Component result = super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus);
208 if (value == null) setText("<no dialect>");
209 return result;
213 if (myExtensionButtons.size() > 0) {
214 myExtensionButtons.get(0).setSelected(true);
216 else {
217 myFileTypeButtons [0].setSelected(true);
220 myChoicesPanel.setLayout(new BorderLayout());
221 myChoicesPanel.add(choicesBox, BorderLayout.CENTER);
223 final ViewerTreeStructure treeStructure = (ViewerTreeStructure)myTreeBuilder.getTreeStructure();
224 myShowWhiteSpacesBox.addActionListener(new ActionListener() {
225 public void actionPerformed(ActionEvent e) {
226 treeStructure.setShowWhiteSpaces(myShowWhiteSpacesBox.isSelected());
227 myTreeBuilder.updateFromRoot();
230 myShowTreeNodesCheckBox.addActionListener(new ActionListener() {
231 public void actionPerformed(ActionEvent e) {
232 treeStructure.setShowTreeNodes(myShowTreeNodesCheckBox.isSelected());
233 myTreeBuilder.updateFromRoot();
236 myTextPanel.setLayout(new BorderLayout());
237 myTextPanel.add(myEditor.getComponent(), BorderLayout.CENTER);
239 super.init();
242 private void updateDialectsCombo() {
243 final SortedComboBoxModel<Language> model = new SortedComboBoxModel<Language>(new Comparator<Language>() {
244 public int compare(final Language o1, final Language o2) {
245 if (o1 == null) return o2 == null? 0 : -1;
246 if (o2 == null) return 1;
247 return o1.getID().compareTo(o2.getID());
250 for (int i = 0; i < myFileTypeButtons.length; i++) {
251 JRadioButton fileTypeButton = myFileTypeButtons[i];
252 if (fileTypeButton.isSelected()) {
253 final FileType type = myFileTypes[i];
254 if (type instanceof LanguageFileType) {
255 final Language baseLang = ((LanguageFileType)type).getLanguage();
256 model.setAll(LanguageUtil.getLanguageDialects(baseLang));
257 model.add(null);
259 break;
262 myDialectsComboBox.setModel(model);
263 myDialectsComboBox.setVisible(model.getSize() > 1);
266 protected JComponent createCenterPanel() {
267 return myPanel;
270 protected void doOKAction() {
271 final String text = myEditor.getDocument().getText();
272 if ("".equals(text.trim())) {
273 return;
275 myLastParsedText = text;
276 PsiElement rootElement = null;
277 try {
278 for (JRadioButton button : myExtensionButtons) {
279 if (button.isSelected()) {
280 PsiViewerExtension ext = (PsiViewerExtension) button.getClientProperty(EXTENSION_KEY);
281 rootElement = ext.createElement(myProject, text);
284 if (rootElement == null) {
285 for (int i = 0; i < myFileTypeButtons.length; i++) {
286 JRadioButton fileTypeButton = myFileTypeButtons[i];
288 if (fileTypeButton.isSelected()) {
289 final FileType type = myFileTypes[i];
290 if (type instanceof LanguageFileType) {
291 final Language language = ((LanguageFileType)type).getLanguage();
292 final Language dialect = (Language)myDialectsComboBox.getSelectedItem();
293 rootElement = PsiFileFactory.getInstance(myProject).createFileFromText("Dummy." + type.getDefaultExtension(), dialect == null? language : dialect, text);
295 else {
296 rootElement = PsiFileFactory.getInstance(myProject).createFileFromText("Dummy." + type.getDefaultExtension(), text);
302 catch (IncorrectOperationException e1) {
303 rootElement = null;
304 Messages.showMessageDialog(
305 myProject,
306 e1.getMessage(),
307 "Error",
308 Messages.getErrorIcon()
311 ViewerTreeStructure structure = (ViewerTreeStructure)myTreeBuilder.getTreeStructure();
312 structure.setRootPsiElement(rootElement);
314 myTreeBuilder.updateFromRoot();
315 myTree.setRootVisible(true);
316 myTree.expandRow(0);
317 myTree.setRootVisible(false);
320 private class MyTreeSelectionListener implements TreeSelectionListener {
321 private final TextAttributes myAttributes;
322 private RangeHighlighter myHighlighter;
324 public MyTreeSelectionListener() {
325 myAttributes = new TextAttributes();
326 myAttributes.setBackgroundColor(new Color(0, 0, 128));
327 myAttributes.setForegroundColor(Color.white);
330 public void valueChanged(TreeSelectionEvent e) {
331 if (!myEditor.getDocument().getText().equals(myLastParsedText)) return;
332 TreePath path = myTree.getSelectionPath();
333 if (path == null){
334 clearSelection();
336 else{
337 clearSelection();
338 DefaultMutableTreeNode node = (DefaultMutableTreeNode)path.getLastPathComponent();
339 if (!(node.getUserObject() instanceof ViewerNodeDescriptor)) return;
340 ViewerNodeDescriptor descriptor = (ViewerNodeDescriptor)node.getUserObject();
341 Object elementObject = descriptor.getElement();
342 final PsiElement element = elementObject instanceof PsiElement? (PsiElement)elementObject :
343 elementObject instanceof ASTNode ? ((ASTNode)elementObject).getPsi() : null;
344 if (element != null) {
345 TextRange range = element.getTextRange();
346 int start = range.getStartOffset();
347 int end = range.getEndOffset();
348 final ViewerTreeStructure treeStructure = (ViewerTreeStructure)myTreeBuilder.getTreeStructure();
349 PsiElement rootPsiElement = treeStructure.getRootPsiElement();
350 if (rootPsiElement != null) {
351 int baseOffset = rootPsiElement.getTextRange().getStartOffset();
352 start -= baseOffset;
353 end -= baseOffset;
356 final int textLength = myEditor.getDocument().getTextLength();
357 if (end <= textLength) {
358 myHighlighter = myEditor.getMarkupModel().addRangeHighlighter(start, end, HighlighterLayer.FIRST + 1, myAttributes, HighlighterTargetArea.EXACT_RANGE);
360 updateReferences(element);
365 public void updateReferences(PsiElement element) {
366 final DefaultListModel model = (DefaultListModel)myRefs.getModel();
367 model.clear();
368 if (element != null) {
369 for (PsiReference reference : element.getReferences()) {
370 model.addElement(reference.getClass().getName());
375 private void clearSelection() {
376 if (myHighlighter != null) {
377 myEditor.getMarkupModel().removeHighlighter(myHighlighter);
378 myHighlighter = null;
383 public void dispose() {
384 Disposer.dispose(myTreeBuilder);
385 EditorFactory.getInstance().releaseEditor(myEditor);
387 super.dispose();
390 private static class GoToListener implements KeyListener, MouseListener {
391 private final JList myList;
392 private final Project myProject;
394 public GoToListener(JList list, Project project) {
395 myList = list;
396 myProject = project;
399 private void navigate() {
400 final Object value = myList.getSelectedValue();
401 if (value instanceof String) {
402 final String fqn = (String)value;
403 String filename = fqn;
404 if (fqn.contains(".")) {
405 filename = fqn.substring(fqn.lastIndexOf('.') + 1);
407 if (filename.contains("$")) {
408 filename = filename.substring(0, filename.indexOf('$'));
410 filename += ".java";
411 final PsiFile[] files = FilenameIndex.getFilesByName(myProject, filename, GlobalSearchScope.allScope(myProject));
412 if (files != null && files.length > 0) {
413 files[0].navigate(true);
418 public void keyPressed(KeyEvent e) {
419 if (e.getKeyCode() == KeyEvent.VK_ENTER) {
420 navigate();
424 public void mouseClicked(MouseEvent e) {
425 if (e.getClickCount() > 1) {
426 navigate();
430 public void keyTyped(KeyEvent e) {}
431 public void keyReleased(KeyEvent e) {}
432 public void mousePressed(MouseEvent e) {}
433 public void mouseReleased(MouseEvent e) {}
434 public void mouseEntered(MouseEvent e) {}
435 public void mouseExited(MouseEvent e) {}