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
.uiDesigner
.palette
;
18 import com
.intellij
.CommonBundle
;
19 import com
.intellij
.ide
.util
.TreeClassChooser
;
20 import com
.intellij
.ide
.util
.TreeClassChooserFactory
;
21 import com
.intellij
.ide
.util
.TreeFileChooser
;
22 import com
.intellij
.openapi
.editor
.Document
;
23 import com
.intellij
.openapi
.fileTypes
.StdFileTypes
;
24 import com
.intellij
.openapi
.help
.HelpManager
;
25 import com
.intellij
.openapi
.module
.ResourceFileUtil
;
26 import com
.intellij
.openapi
.project
.Project
;
27 import com
.intellij
.openapi
.ui
.ComponentWithBrowseButton
;
28 import com
.intellij
.openapi
.ui
.DialogWrapper
;
29 import com
.intellij
.openapi
.ui
.Messages
;
30 import com
.intellij
.openapi
.ui
.TextFieldWithBrowseButton
;
31 import com
.intellij
.openapi
.vfs
.VirtualFile
;
32 import com
.intellij
.psi
.*;
33 import com
.intellij
.psi
.search
.GlobalSearchScope
;
34 import com
.intellij
.psi
.search
.ProjectScope
;
35 import com
.intellij
.psi
.util
.InheritanceUtil
;
36 import com
.intellij
.psi
.util
.PsiTreeUtil
;
37 import com
.intellij
.ui
.DocumentAdapter
;
38 import com
.intellij
.ui
.EditorTextField
;
39 import com
.intellij
.uiDesigner
.FormEditingUtil
;
40 import com
.intellij
.uiDesigner
.ImageFileFilter
;
41 import com
.intellij
.uiDesigner
.UIDesignerBundle
;
42 import com
.intellij
.uiDesigner
.compiler
.Utils
;
43 import com
.intellij
.uiDesigner
.core
.GridConstraints
;
44 import com
.intellij
.uiDesigner
.lw
.LwRootContainer
;
45 import org
.jetbrains
.annotations
.NotNull
;
48 import javax
.swing
.event
.ChangeEvent
;
49 import javax
.swing
.event
.ChangeListener
;
50 import javax
.swing
.event
.DocumentEvent
;
52 import java
.awt
.event
.ActionEvent
;
53 import java
.awt
.event
.ActionListener
;
54 import java
.awt
.event
.ItemEvent
;
55 import java
.awt
.event
.ItemListener
;
56 import java
.util
.ArrayList
;
59 * @author Vladimir Kondratyev
61 public final class ComponentItemDialog
extends DialogWrapper
{
62 private JPanel myPanel
;
63 private final ComponentWithBrowseButton
<EditorTextField
> myTfClassName
;
64 private final Project myProject
;
65 private final ComponentItem myItemToBeEdited
;
66 private final boolean myOneOff
;
67 private JLabel myLblIcon
;
68 private TextFieldWithBrowseButton myTfIconPath
;
69 private JCheckBox myChkHorCanShrink
;
70 private JCheckBox myChkHorCanGrow
;
71 private JCheckBox myChkHorWantGrow
;
72 private JCheckBox myChkVerCanShrink
;
73 private JCheckBox myChkVerCanGrow
;
74 private JCheckBox myChkVerWantGrow
;
75 private JPanel myClassNamePlaceholder
;
76 private JRadioButton myClassRadioButton
;
77 private JRadioButton myNestedFormRadioButton
;
78 private TextFieldWithBrowseButton myTfNestedForm
;
79 private JCheckBox myAutoCreateBindingCheckbox
;
80 private JCheckBox myCanAttachLabelCheckbox
;
81 private JPanel myHSizePolicyPanel
;
82 private JPanel myVSizePolicyPanel
;
83 private JComboBox myGroupComboBox
;
84 private JLabel myGroupLabel
;
85 private JCheckBox myIsContainerCheckBox
;
86 private JLabel myErrorLabel
;
87 private final EditorTextField myEditorTextField
;
88 private Document myDocument
;
91 * @param itemToBeEdited item to be edited. If user closes dialog by "OK" button then
94 public ComponentItemDialog(final Project project
, final Component parent
, @NotNull ComponentItem itemToBeEdited
, final boolean oneOff
) {
98 myItemToBeEdited
= itemToBeEdited
;
101 myEditorTextField
= new EditorTextField("", project
, StdFileTypes
.JAVA
);
102 myEditorTextField
.setFontInheritedFromLAF(true);
103 myTfClassName
= new ComponentWithBrowseButton
<EditorTextField
>(myEditorTextField
, new MyChooseClassActionListener(project
));
105 PsiFile boundForm
= itemToBeEdited
.getBoundForm();
106 if (boundForm
!= null) {
107 myNestedFormRadioButton
.setSelected(true);
108 myTfNestedForm
.setText(FormEditingUtil
.buildResourceName(boundForm
));
111 myClassRadioButton
.setSelected(true);
112 setEditorText(myItemToBeEdited
.getClassName().replace('$', '.'));
114 updateEnabledTextField();
116 myTfClassName
.getChildComponent().addDocumentListener(new com
.intellij
.openapi
.editor
.event
.DocumentAdapter() {
117 public void documentChanged(com
.intellij
.openapi
.editor
.event
.DocumentEvent e
) {
122 myTfClassName
.getButton().setEnabled(!project
.isDefault()); // chooser should not work in default project
123 myClassNamePlaceholder
.setLayout(new BorderLayout());
124 myClassNamePlaceholder
.add(myTfClassName
, BorderLayout
.CENTER
);
126 myTfIconPath
.setText(myItemToBeEdited
.getIconPath());
127 myTfIconPath
.addActionListener(new MyChooseFileActionListener(project
, new ImageFileFilter(null), myTfIconPath
,
128 UIDesignerBundle
.message("add.component.choose.icon")));
130 myTfNestedForm
.addActionListener(new MyChooseFileActionListener(project
, new TreeFileChooser
.PsiFileFilter() {
131 public boolean accept(PsiFile file
) {
132 return file
.getFileType().equals(StdFileTypes
.GUI_DESIGNER_FORM
);
134 }, myTfNestedForm
, UIDesignerBundle
.message("add.component.choose.form")));
136 myTfNestedForm
.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
137 protected void textChanged(DocumentEvent e
) {
142 final GridConstraints defaultConstraints
= myItemToBeEdited
.getDefaultConstraints();
144 // Horizontal size policy
146 final int hSizePolicy
= defaultConstraints
.getHSizePolicy();
147 myChkHorCanShrink
.setSelected((hSizePolicy
& GridConstraints
.SIZEPOLICY_CAN_SHRINK
) != 0);
148 myChkHorCanGrow
.setSelected((hSizePolicy
& GridConstraints
.SIZEPOLICY_CAN_GROW
) != 0);
149 myChkHorWantGrow
.setSelected((hSizePolicy
& GridConstraints
.SIZEPOLICY_WANT_GROW
) != 0);
152 // Vertical size policy
154 final int vSizePolicy
= defaultConstraints
.getVSizePolicy();
155 myChkVerCanShrink
.setSelected((vSizePolicy
& GridConstraints
.SIZEPOLICY_CAN_SHRINK
) != 0);
156 myChkVerCanGrow
.setSelected((vSizePolicy
& GridConstraints
.SIZEPOLICY_CAN_GROW
) != 0);
157 myChkVerWantGrow
.setSelected((vSizePolicy
& GridConstraints
.SIZEPOLICY_WANT_GROW
) != 0);
160 myIsContainerCheckBox
.setSelected(itemToBeEdited
.isContainer());
161 myAutoCreateBindingCheckbox
.setSelected(itemToBeEdited
.isAutoCreateBinding());
162 myCanAttachLabelCheckbox
.setSelected(itemToBeEdited
.isCanAttachLabel());
164 myLblIcon
.setLabelFor(myTfIconPath
);
165 myClassRadioButton
.addChangeListener(new MyRadioChangeListener());
166 myNestedFormRadioButton
.addChangeListener(new MyRadioChangeListener());
169 myLblIcon
.setVisible(false);
170 myTfIconPath
.setVisible(false);
171 myCanAttachLabelCheckbox
.setVisible(false);
172 myHSizePolicyPanel
.setVisible(false);
173 myVSizePolicyPanel
.setVisible(false);
181 void showGroupChooser(GroupItem defaultGroup
) {
182 myGroupLabel
.setVisible(true);
183 myGroupComboBox
.setVisible(true);
184 final ArrayList
<GroupItem
> groups
= Palette
.getInstance(myProject
).getGroups();
185 myGroupComboBox
.setModel(new DefaultComboBoxModel(groups
.toArray()));
186 myGroupComboBox
.setSelectedItem(defaultGroup
);
187 myGroupComboBox
.addItemListener(new ItemListener() {
188 public void itemStateChanged(ItemEvent e
) {
195 GroupItem
getSelectedGroup() {
196 return (GroupItem
) myGroupComboBox
.getSelectedItem();
199 private void setEditorText(final String className
) {
200 final PsiManager manager
= PsiManager
.getInstance(myProject
);
201 final PsiElementFactory factory
= JavaPsiFacade
.getInstance(manager
.getProject()).getElementFactory();
202 PsiPackage defaultPackage
= JavaPsiFacade
.getInstance(manager
.getProject()).findPackage("");
203 final PsiCodeFragment fragment
= factory
.createReferenceCodeFragment(className
, defaultPackage
, true, true);
204 myDocument
= PsiDocumentManager
.getInstance(manager
.getProject()).getDocument(fragment
);
205 myEditorTextField
.setDocument(myDocument
);
209 protected Action
[] createActions() {
210 return new Action
[]{getOKAction(), getCancelAction(), getHelpAction()};
213 protected void doHelpAction() {
214 HelpManager
.getInstance().invokeHelp("reference.dialogs.addEditPaletteComponent");
217 protected void doOKAction() {
218 // TODO[vova] implement validation
219 if (myClassRadioButton
.isSelected()) {
220 final String className
= myDocument
.getText().trim();
221 PsiClass psiClass
= JavaPsiFacade
.getInstance(myProject
).findClass(className
, GlobalSearchScope
.allScope(myProject
));
222 if (psiClass
!= null) {
223 myItemToBeEdited
.setClassName(getClassOrInnerName(psiClass
));
226 myItemToBeEdited
.setClassName(className
);
230 if (!saveNestedForm()) return;
232 myItemToBeEdited
.setIconPath(myTfIconPath
.getText().trim());
235 final GridConstraints defaultConstraints
= myItemToBeEdited
.getDefaultConstraints();
236 // Horizontal size policy
237 defaultConstraints
.setHSizePolicy(
238 (myChkHorCanShrink
.isSelected() ? GridConstraints
.SIZEPOLICY_CAN_SHRINK
: 0) |
239 (myChkHorCanGrow
.isSelected() ? GridConstraints
.SIZEPOLICY_CAN_GROW
: 0) |
240 (myChkHorWantGrow
.isSelected() ? GridConstraints
.SIZEPOLICY_WANT_GROW
: 0)
243 // Vertical size policy
244 defaultConstraints
.setVSizePolicy(
245 (myChkVerCanShrink
.isSelected() ? GridConstraints
.SIZEPOLICY_CAN_SHRINK
: 0) |
246 (myChkVerCanGrow
.isSelected() ? GridConstraints
.SIZEPOLICY_CAN_GROW
: 0) |
247 (myChkVerWantGrow
.isSelected() ? GridConstraints
.SIZEPOLICY_WANT_GROW
: 0)
250 defaultConstraints
.setFill(
251 (myChkHorWantGrow
.isSelected() ? GridConstraints
.FILL_HORIZONTAL
: 0) |
252 (myChkVerWantGrow
.isSelected() ? GridConstraints
.FILL_VERTICAL
: 0)
256 myItemToBeEdited
.setIsContainer(myIsContainerCheckBox
.isSelected());
257 myItemToBeEdited
.setAutoCreateBinding(myAutoCreateBindingCheckbox
.isSelected());
258 myItemToBeEdited
.setCanAttachLabel(myCanAttachLabelCheckbox
.isSelected());
263 private boolean saveNestedForm() {
264 VirtualFile formFile
= ResourceFileUtil
.findResourceFileInProject(myProject
, myTfNestedForm
.getText());
265 if (formFile
== null) {
266 Messages
.showErrorDialog(getWindow(), UIDesignerBundle
.message("add.component.cannot.load.form", myTfNestedForm
.getText()), CommonBundle
.getErrorTitle());
269 LwRootContainer lwRootContainer
;
271 lwRootContainer
= Utils
.getRootContainer(formFile
.getInputStream(), null);
273 catch (Exception e
) {
274 Messages
.showErrorDialog(getWindow(), e
.getMessage(), CommonBundle
.getErrorTitle());
277 if (lwRootContainer
.getClassToBind() == null) {
278 Messages
.showErrorDialog(getWindow(), UIDesignerBundle
.message("add.component.form.not.bound"), CommonBundle
.getErrorTitle());
281 if (lwRootContainer
.getComponent(0).getBinding() == null) {
282 Messages
.showErrorDialog(getWindow(), UIDesignerBundle
.message("add.component.root.not.bound"),
283 CommonBundle
.getErrorTitle());
287 JavaPsiFacade
.getInstance(myProject
).findClass(lwRootContainer
.getClassToBind(), GlobalSearchScope
.projectScope(myProject
));
288 if (psiClass
!= null) {
289 myItemToBeEdited
.setClassName(getClassOrInnerName(psiClass
));
292 myItemToBeEdited
.setClassName(lwRootContainer
.getClassToBind());
297 protected String
getDimensionServiceKey() {
299 return "#com.intellij.uiDesigner.palette.ComponentItemDialog.OneOff";
301 return "#com.intellij.uiDesigner.palette.ComponentItemDialog";
304 public JComponent
getPreferredFocusedComponent() {
305 return myTfClassName
.getChildComponent();
308 protected JComponent
createCenterPanel() {
312 private void updateEnabledTextField() {
313 myEditorTextField
.setEnabled(myClassRadioButton
.isSelected());
314 myTfNestedForm
.setEnabled(myNestedFormRadioButton
.isSelected());
318 private void updateOKAction() {
319 setOKActionEnabled(isOKEnabled());
322 private boolean isOKEnabled() {
323 myErrorLabel
.setText(" ");
324 if (myClassRadioButton
.isSelected()) {
325 final PsiManager psiManager
= PsiManager
.getInstance(myProject
);
326 if (!JavaPsiFacade
.getInstance(psiManager
.getProject()).getNameHelper().isQualifiedName(myDocument
.getText())) {
327 if (myDocument
.getTextLength() > 0) {
328 myErrorLabel
.setText(UIDesignerBundle
.message("add.component.error.qualified.name.required"));
333 JavaPsiFacade
.getInstance(psiManager
.getProject()).findClass(myDocument
.getText(), ProjectScope
.getAllScope(myProject
));
334 PsiClass componentClass
=
335 JavaPsiFacade
.getInstance(psiManager
.getProject()).findClass(JComponent
.class.getName(), ProjectScope
.getAllScope(myProject
));
336 if (psiClass
!= null && componentClass
!= null && !InheritanceUtil
.isInheritorOrSelf(psiClass
, componentClass
, true)) {
337 myErrorLabel
.setText(UIDesignerBundle
.message("add.component.error.component.required"));
342 if (myTfNestedForm
.getText().length() == 0) {
346 if (myGroupComboBox
.isVisible() && myGroupComboBox
.getSelectedItem() == null) {
352 private static String
getClassOrInnerName(final PsiClass aClass
) {
353 PsiClass parentClass
= PsiTreeUtil
.getParentOfType(aClass
, PsiClass
.class, true);
354 if(parentClass
!= null) {
355 return getClassOrInnerName(parentClass
) + "$" + aClass
.getName();
357 return aClass
.getQualifiedName();
360 private class MyChooseClassActionListener
implements ActionListener
{
361 private final Project myProject
;
363 public MyChooseClassActionListener(final Project project
) {
367 public void actionPerformed(final ActionEvent e
) {
368 final TreeClassChooserFactory factory
= TreeClassChooserFactory
.getInstance(myProject
);
369 final TreeClassChooser chooser
= factory
.createInheritanceClassChooser(UIDesignerBundle
.message("title.choose.component.class"),
370 GlobalSearchScope
.allScope(myProject
), JavaPsiFacade
.getInstance(myProject
).findClass(
371 JComponent
.class.getName(), GlobalSearchScope
.allScope(myProject
)), true, true, null);
372 chooser
.showDialog();
373 final PsiClass result
= chooser
.getSelectedClass();
374 if (result
!= null) {
375 setEditorText(result
.getQualifiedName());
380 private static class MyChooseFileActionListener
implements ActionListener
{
381 private final Project myProject
;
382 private final TreeFileChooser
.PsiFileFilter myFilter
;
383 private final TextFieldWithBrowseButton myTextField
;
384 private final String myTitle
;
386 public MyChooseFileActionListener(final Project project
,
387 final TreeFileChooser
.PsiFileFilter filter
,
388 final TextFieldWithBrowseButton textField
,
389 final String title
) {
392 myTextField
= textField
;
396 public void actionPerformed(ActionEvent e
) {
397 final TreeClassChooserFactory factory
= TreeClassChooserFactory
.getInstance(myProject
);
398 PsiFile formFile
= null;
399 if (myTextField
.getText().length() > 0) {
400 VirtualFile formVFile
= ResourceFileUtil
.findResourceFileInScope(myTextField
.getText(), myProject
, ProjectScope
.getAllScope(myProject
));
401 if (formVFile
!= null) {
402 formFile
= PsiManager
.getInstance(myProject
).findFile(formVFile
);
405 TreeFileChooser fileChooser
= factory
.createFileChooser(myTitle
, formFile
, null, myFilter
, true, true);
406 fileChooser
.showDialog();
407 PsiFile file
= fileChooser
.getSelectedFile();
409 myTextField
.setText(FormEditingUtil
.buildResourceName(file
));
414 private class MyRadioChangeListener
implements ChangeListener
{
415 public void stateChanged(ChangeEvent e
) {
416 updateEnabledTextField();