blob: a3d66a914304ab5314b7534c951acea1eba34d9b [file] [log] [blame]
/*
* Copyright 2000-2009 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.intellij.uiDesigner.palette;
import com.intellij.CommonBundle;
import com.intellij.ide.util.TreeClassChooser;
import com.intellij.ide.util.TreeClassChooserFactory;
import com.intellij.ide.util.TreeFileChooser;
import com.intellij.openapi.editor.Document;
import com.intellij.openapi.fileTypes.StdFileTypes;
import com.intellij.openapi.help.HelpManager;
import com.intellij.openapi.module.ResourceFileUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.ComponentWithBrowseButton;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.TextFieldWithBrowseButton;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.ProjectScope;
import com.intellij.psi.util.InheritanceUtil;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.ui.DocumentAdapter;
import com.intellij.ui.EditorTextField;
import com.intellij.uiDesigner.FormEditingUtil;
import com.intellij.uiDesigner.ImageFileFilter;
import com.intellij.uiDesigner.UIDesignerBundle;
import com.intellij.uiDesigner.compiler.Utils;
import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.lw.LwRootContainer;
import org.jetbrains.annotations.NotNull;
import javax.swing.*;
import javax.swing.event.ChangeEvent;
import javax.swing.event.ChangeListener;
import javax.swing.event.DocumentEvent;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.ItemEvent;
import java.awt.event.ItemListener;
import java.util.ArrayList;
/**
* @author Vladimir Kondratyev
*/
public final class ComponentItemDialog extends DialogWrapper {
private JPanel myPanel;
private final ComponentWithBrowseButton<EditorTextField> myTfClassName;
private final Project myProject;
private final ComponentItem myItemToBeEdited;
private final boolean myOneOff;
private JLabel myLblIcon;
private TextFieldWithBrowseButton myTfIconPath;
private JCheckBox myChkHorCanShrink;
private JCheckBox myChkHorCanGrow;
private JCheckBox myChkHorWantGrow;
private JCheckBox myChkVerCanShrink;
private JCheckBox myChkVerCanGrow;
private JCheckBox myChkVerWantGrow;
private JPanel myClassNamePlaceholder;
private JRadioButton myClassRadioButton;
private JRadioButton myNestedFormRadioButton;
private TextFieldWithBrowseButton myTfNestedForm;
private JCheckBox myAutoCreateBindingCheckbox;
private JCheckBox myCanAttachLabelCheckbox;
private JPanel myHSizePolicyPanel;
private JPanel myVSizePolicyPanel;
private JComboBox myGroupComboBox;
private JLabel myGroupLabel;
private JCheckBox myIsContainerCheckBox;
private JLabel myErrorLabel;
private final EditorTextField myEditorTextField;
private Document myDocument;
/**
* @param itemToBeEdited item to be edited. If user closes dialog by "OK" button then
* @param oneOff
*/
public ComponentItemDialog(final Project project, final Component parent, @NotNull ComponentItem itemToBeEdited, final boolean oneOff) {
super(parent, false);
myProject = project;
myItemToBeEdited = itemToBeEdited;
myOneOff = oneOff;
myEditorTextField = new EditorTextField("", project, StdFileTypes.JAVA);
myEditorTextField.setFontInheritedFromLAF(true);
myTfClassName = new ComponentWithBrowseButton<EditorTextField>(myEditorTextField, new MyChooseClassActionListener(project));
PsiFile boundForm = itemToBeEdited.getBoundForm();
if (boundForm != null) {
myNestedFormRadioButton.setSelected(true);
myTfNestedForm.setText(FormEditingUtil.buildResourceName(boundForm));
}
else {
myClassRadioButton.setSelected(true);
setEditorText(myItemToBeEdited.getClassName().replace('$', '.'));
}
updateEnabledTextField();
myTfClassName.getChildComponent().addDocumentListener(new com.intellij.openapi.editor.event.DocumentAdapter() {
public void documentChanged(com.intellij.openapi.editor.event.DocumentEvent e) {
updateOKAction();
}
});
myTfClassName.getButton().setEnabled(!project.isDefault()); // chooser should not work in default project
myClassNamePlaceholder.setLayout(new BorderLayout());
myClassNamePlaceholder.add(myTfClassName, BorderLayout.CENTER);
myTfIconPath.setText(myItemToBeEdited.getIconPath());
myTfIconPath.addActionListener(new MyChooseFileActionListener(project, new ImageFileFilter(null), myTfIconPath,
UIDesignerBundle.message("add.component.choose.icon")));
myTfNestedForm.addActionListener(new MyChooseFileActionListener(project, new TreeFileChooser.PsiFileFilter() {
public boolean accept(PsiFile file) {
return file.getFileType().equals(StdFileTypes.GUI_DESIGNER_FORM);
}
}, myTfNestedForm, UIDesignerBundle.message("add.component.choose.form")));
myTfNestedForm.getTextField().getDocument().addDocumentListener(new DocumentAdapter() {
protected void textChanged(DocumentEvent e) {
updateOKAction();
}
});
final GridConstraints defaultConstraints = myItemToBeEdited.getDefaultConstraints();
// Horizontal size policy
{
final int hSizePolicy = defaultConstraints.getHSizePolicy();
myChkHorCanShrink.setSelected((hSizePolicy & GridConstraints.SIZEPOLICY_CAN_SHRINK) != 0);
myChkHorCanGrow.setSelected((hSizePolicy & GridConstraints.SIZEPOLICY_CAN_GROW) != 0);
myChkHorWantGrow.setSelected((hSizePolicy & GridConstraints.SIZEPOLICY_WANT_GROW) != 0);
}
// Vertical size policy
{
final int vSizePolicy = defaultConstraints.getVSizePolicy();
myChkVerCanShrink.setSelected((vSizePolicy & GridConstraints.SIZEPOLICY_CAN_SHRINK) != 0);
myChkVerCanGrow.setSelected((vSizePolicy & GridConstraints.SIZEPOLICY_CAN_GROW) != 0);
myChkVerWantGrow.setSelected((vSizePolicy & GridConstraints.SIZEPOLICY_WANT_GROW) != 0);
}
myIsContainerCheckBox.setSelected(itemToBeEdited.isContainer());
myAutoCreateBindingCheckbox.setSelected(itemToBeEdited.isAutoCreateBinding());
myCanAttachLabelCheckbox.setSelected(itemToBeEdited.isCanAttachLabel());
myLblIcon.setLabelFor(myTfIconPath);
myClassRadioButton.addChangeListener(new MyRadioChangeListener());
myNestedFormRadioButton.addChangeListener(new MyRadioChangeListener());
if (oneOff) {
myLblIcon.setVisible(false);
myTfIconPath.setVisible(false);
myCanAttachLabelCheckbox.setVisible(false);
myHSizePolicyPanel.setVisible(false);
myVSizePolicyPanel.setVisible(false);
}
updateOKAction();
init();
}
void showGroupChooser(GroupItem defaultGroup) {
myGroupLabel.setVisible(true);
myGroupComboBox.setVisible(true);
final ArrayList<GroupItem> groups = Palette.getInstance(myProject).getGroups();
myGroupComboBox.setModel(new DefaultComboBoxModel(groups.toArray()));
myGroupComboBox.setSelectedItem(defaultGroup);
myGroupComboBox.addItemListener(new ItemListener() {
public void itemStateChanged(ItemEvent e) {
updateOKAction();
}
});
updateOKAction();
}
GroupItem getSelectedGroup() {
return (GroupItem) myGroupComboBox.getSelectedItem();
}
private void setEditorText(final String className) {
final JavaCodeFragmentFactory factory = JavaCodeFragmentFactory.getInstance(myProject);
PsiPackage defaultPackage = JavaPsiFacade.getInstance(myProject).findPackage("");
final PsiCodeFragment fragment = factory.createReferenceCodeFragment(className, defaultPackage, true, true);
myDocument = PsiDocumentManager.getInstance(myProject).getDocument(fragment);
myEditorTextField.setDocument(myDocument);
updateOKAction();
}
@NotNull
protected Action[] createActions() {
return new Action[]{getOKAction(), getCancelAction(), getHelpAction()};
}
protected void doHelpAction() {
HelpManager.getInstance().invokeHelp("reference.dialogs.addEditPaletteComponent");
}
protected void doOKAction() {
// TODO[vova] implement validation
if (myClassRadioButton.isSelected()) {
final String className = myDocument.getText().trim();
PsiClass psiClass = JavaPsiFacade.getInstance(myProject).findClass(className, GlobalSearchScope.allScope(myProject));
if (psiClass != null) {
myItemToBeEdited.setClassName(getClassOrInnerName(psiClass));
}
else {
myItemToBeEdited.setClassName(className);
}
}
else {
if (!saveNestedForm()) return;
}
myItemToBeEdited.setIconPath(myTfIconPath.getText().trim());
{
final GridConstraints defaultConstraints = myItemToBeEdited.getDefaultConstraints();
// Horizontal size policy
defaultConstraints.setHSizePolicy(
(myChkHorCanShrink.isSelected() ? GridConstraints.SIZEPOLICY_CAN_SHRINK : 0) |
(myChkHorCanGrow.isSelected() ? GridConstraints.SIZEPOLICY_CAN_GROW : 0) |
(myChkHorWantGrow.isSelected() ? GridConstraints.SIZEPOLICY_WANT_GROW : 0)
);
// Vertical size policy
defaultConstraints.setVSizePolicy(
(myChkVerCanShrink.isSelected() ? GridConstraints.SIZEPOLICY_CAN_SHRINK : 0) |
(myChkVerCanGrow.isSelected() ? GridConstraints.SIZEPOLICY_CAN_GROW : 0) |
(myChkVerWantGrow.isSelected() ? GridConstraints.SIZEPOLICY_WANT_GROW : 0)
);
defaultConstraints.setFill(
(myChkHorWantGrow.isSelected() ? GridConstraints.FILL_HORIZONTAL : 0) |
(myChkVerWantGrow.isSelected() ? GridConstraints.FILL_VERTICAL : 0)
);
}
myItemToBeEdited.setIsContainer(myIsContainerCheckBox.isSelected());
myItemToBeEdited.setAutoCreateBinding(myAutoCreateBindingCheckbox.isSelected());
myItemToBeEdited.setCanAttachLabel(myCanAttachLabelCheckbox.isSelected());
super.doOKAction();
}
private boolean saveNestedForm() {
VirtualFile formFile = ResourceFileUtil.findResourceFileInProject(myProject, myTfNestedForm.getText());
if (formFile == null) {
Messages.showErrorDialog(getWindow(), UIDesignerBundle.message("add.component.cannot.load.form", myTfNestedForm.getText()), CommonBundle.getErrorTitle());
return false;
}
LwRootContainer lwRootContainer;
try {
lwRootContainer = Utils.getRootContainer(formFile.getInputStream(), null);
}
catch (Exception e) {
Messages.showErrorDialog(getWindow(), e.getMessage(), CommonBundle.getErrorTitle());
return false;
}
if (lwRootContainer.getClassToBind() == null) {
Messages.showErrorDialog(getWindow(), UIDesignerBundle.message("add.component.form.not.bound"), CommonBundle.getErrorTitle());
return false;
}
if (lwRootContainer.getComponent(0).getBinding() == null) {
Messages.showErrorDialog(getWindow(), UIDesignerBundle.message("add.component.root.not.bound"),
CommonBundle.getErrorTitle());
return false;
}
PsiClass psiClass =
JavaPsiFacade.getInstance(myProject).findClass(lwRootContainer.getClassToBind(), GlobalSearchScope.projectScope(myProject));
if (psiClass != null) {
myItemToBeEdited.setClassName(getClassOrInnerName(psiClass));
}
else {
myItemToBeEdited.setClassName(lwRootContainer.getClassToBind());
}
return true;
}
protected String getDimensionServiceKey() {
if (myOneOff) {
return "#com.intellij.uiDesigner.palette.ComponentItemDialog.OneOff";
}
return "#com.intellij.uiDesigner.palette.ComponentItemDialog";
}
public JComponent getPreferredFocusedComponent() {
return myTfClassName.getChildComponent();
}
protected JComponent createCenterPanel() {
return myPanel;
}
private void updateEnabledTextField() {
myEditorTextField.setEnabled(myClassRadioButton.isSelected());
myTfNestedForm.setEnabled(myNestedFormRadioButton.isSelected());
updateOKAction();
}
private void updateOKAction() {
setOKActionEnabled(isOKEnabled());
}
private boolean isOKEnabled() {
myErrorLabel.setText(" ");
if (myClassRadioButton.isSelected()) {
if (myDocument == null) { // why?
return false;
}
if (!PsiNameHelper.getInstance(myProject).isQualifiedName(myDocument.getText())) {
if (myDocument.getTextLength() > 0) {
myErrorLabel.setText(UIDesignerBundle.message("add.component.error.qualified.name.required"));
}
return false;
}
final JavaPsiFacade javaPsiFacade = JavaPsiFacade.getInstance(myProject);
PsiClass psiClass = javaPsiFacade.findClass(myDocument.getText(), ProjectScope.getAllScope(myProject));
PsiClass componentClass = javaPsiFacade.findClass(JComponent.class.getName(), ProjectScope.getAllScope(myProject));
if (psiClass != null && componentClass != null && !InheritanceUtil.isInheritorOrSelf(psiClass, componentClass, true)) {
myErrorLabel.setText(UIDesignerBundle.message("add.component.error.component.required"));
return false;
}
}
else {
if (myTfNestedForm.getText().length() == 0) {
return false;
}
}
if (myGroupComboBox.isVisible() && myGroupComboBox.getSelectedItem() == null) {
return false;
}
return true;
}
private static String getClassOrInnerName(final PsiClass aClass) {
PsiClass parentClass = PsiTreeUtil.getParentOfType(aClass, PsiClass.class, true);
if(parentClass != null) {
return getClassOrInnerName(parentClass) + "$" + aClass.getName();
}
return aClass.getQualifiedName();
}
private class MyChooseClassActionListener implements ActionListener {
private final Project myProject;
public MyChooseClassActionListener(final Project project) {
myProject = project;
}
public void actionPerformed(final ActionEvent e) {
final TreeClassChooserFactory factory = TreeClassChooserFactory.getInstance(myProject);
final TreeClassChooser chooser = factory.createInheritanceClassChooser(UIDesignerBundle.message("title.choose.component.class"),
GlobalSearchScope.allScope(myProject), JavaPsiFacade.getInstance(myProject).findClass(
JComponent.class.getName(), GlobalSearchScope.allScope(myProject)), true, true, null);
chooser.showDialog();
final PsiClass result = chooser.getSelected();
if (result != null) {
setEditorText(result.getQualifiedName());
}
}
}
private static class MyChooseFileActionListener implements ActionListener {
private final Project myProject;
private final TreeFileChooser.PsiFileFilter myFilter;
private final TextFieldWithBrowseButton myTextField;
private final String myTitle;
public MyChooseFileActionListener(final Project project,
final TreeFileChooser.PsiFileFilter filter,
final TextFieldWithBrowseButton textField,
final String title) {
myProject = project;
myFilter = filter;
myTextField = textField;
myTitle = title;
}
public void actionPerformed(ActionEvent e) {
final TreeClassChooserFactory factory = TreeClassChooserFactory.getInstance(myProject);
PsiFile formFile = null;
if (myTextField.getText().length() > 0) {
VirtualFile formVFile = ResourceFileUtil.findResourceFileInScope(myTextField.getText(), myProject, ProjectScope.getAllScope(myProject));
if (formVFile != null) {
formFile = PsiManager.getInstance(myProject).findFile(formVFile);
}
}
TreeFileChooser fileChooser = factory.createFileChooser(myTitle, formFile, null, myFilter, true, true);
fileChooser.showDialog();
PsiFile file = fileChooser.getSelectedFile();
if (file != null) {
myTextField.setText(FormEditingUtil.buildResourceName(file));
}
}
}
private class MyRadioChangeListener implements ChangeListener {
public void stateChanged(ChangeEvent e) {
updateEnabledTextField();
}
}
}