replaced <code></code> with more concise {@code}
[idea/community.git] / plugins / ui-designer / src / com / intellij / uiDesigner / quickFixes / CreateFieldFix.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 package com.intellij.uiDesigner.quickFixes;
17
18 import com.intellij.CommonBundle;
19 import com.intellij.openapi.application.ApplicationManager;
20 import com.intellij.openapi.command.CommandProcessor;
21 import com.intellij.openapi.diagnostic.Logger;
22 import com.intellij.openapi.project.Project;
23 import com.intellij.openapi.ui.Messages;
24 import com.intellij.psi.*;
25 import com.intellij.psi.search.GlobalSearchScope;
26 import com.intellij.refactoring.util.CommonRefactoringUtil;
27 import com.intellij.uiDesigner.FormEditingUtil;
28 import com.intellij.uiDesigner.GuiDesignerConfiguration;
29 import com.intellij.uiDesigner.UIDesignerBundle;
30 import com.intellij.uiDesigner.designSurface.GuiEditor;
31 import com.intellij.uiDesigner.lw.IContainer;
32 import com.intellij.uiDesigner.radComponents.RadContainer;
33 import com.intellij.util.IncorrectOperationException;
34 import org.jetbrains.annotations.NotNull;
35 import org.jetbrains.annotations.Nullable;
36
37 /**
38  * @author Anton Katilin
39  * @author Vladimir Kondratyev
40  */
41 public final class CreateFieldFix extends QuickFix{
42   private static final Logger LOG = Logger.getInstance("#com.intellij.uiDesigner.quickFixes.CreateFieldFix");
43
44   private final PsiClass myClass;
45   private final String myFieldClassName;
46   private final String myFieldName;
47
48   public CreateFieldFix(
49     final GuiEditor editor,
50     @NotNull final PsiClass aClass,
51     @NotNull final String fieldClass,
52     @NotNull final String fieldName
53   ) {
54     super(editor, UIDesignerBundle.message("action.create.field", fieldName), null);
55     myClass = aClass;
56     myFieldClassName = fieldClass;
57     myFieldName = fieldName;
58   }
59
60   /**
61    * @param showErrors if {@code true} the error messages will be shown to the
62    * @param undoGroupId the group used to undo the action together with some other action.
63    */
64   public static void runImpl(@NotNull final Project project,
65                              @NotNull final RadContainer rootContainer,
66                              @NotNull final PsiClass boundClass,
67                              @NotNull final String fieldClassName,
68                              @NotNull final String fieldName,
69                              final boolean showErrors,
70                              @Nullable final Object undoGroupId) {
71     ApplicationManager.getApplication().assertReadAccessAllowed();
72
73     PsiDocumentManager.getInstance(project).commitAllDocuments();
74
75     // Do nothing if file becomes invalid
76     if(!boundClass.isValid()){
77       return;
78     }
79
80     if(!boundClass.isWritable()){
81       if(showErrors) {
82         if (!CommonRefactoringUtil.checkReadOnlyStatus(boundClass, project,
83                                                        UIDesignerBundle.message("error.cannot.create.field", fieldClassName))) {
84           return;
85         }
86       } else return;
87     }
88
89     final PsiClass fieldClass = JavaPsiFacade.getInstance(project)
90       .findClass(fieldClassName.replace('$', '.'), GlobalSearchScope.moduleWithDependenciesAndLibrariesScope(rootContainer.getModule()));
91     if(fieldClass == null){
92       if(showErrors){
93         Messages.showErrorDialog(
94           project,
95           UIDesignerBundle.message("error.cannot.create.field.no.class", fieldName, fieldClassName),
96           CommonBundle.getErrorTitle()
97         );
98       }
99       return;
100     }
101
102     CommandProcessor.getInstance().executeCommand(
103       project,
104       () -> ApplicationManager.getApplication().runWriteAction(
105         () -> createField(project, fieldClass, fieldName, boundClass, showErrors, rootContainer)
106       ),
107       UIDesignerBundle.message("command.create.field"),
108       undoGroupId
109     );
110   }
111
112   private static void createField(final Project project,
113                                   final PsiClass fieldClass,
114                                   final String fieldName,
115                                   final PsiClass boundClass,
116                                   final boolean showErrors,
117                                   final IContainer rootContainer) {
118     // 1. Create field
119     final PsiElementFactory factory = JavaPsiFacade.getInstance(project).getElementFactory();
120     final PsiType type = factory.createType(fieldClass);
121     try {
122       final PsiField field = factory.createField(fieldName, type);
123       final String accessibility = GuiDesignerConfiguration.getInstance(project).DEFAULT_FIELD_ACCESSIBILITY;
124       final PsiModifierList modifierList = field.getModifierList();
125       assert modifierList != null;
126       String[] modifiers = {PsiModifier.PRIVATE, PsiModifier.PROTECTED, PsiModifier.PUBLIC};
127       for(@PsiModifier.ModifierConstant String modifier: modifiers) {
128         modifierList.setModifierProperty(modifier, accessibility.equals(modifier));
129       }
130       PsiField lastUiField = null;
131       for(PsiField uiField: boundClass.getFields()) {
132         if (FormEditingUtil.findComponentWithBinding(rootContainer, uiField.getName()) != null) {
133           lastUiField = uiField;
134         }
135       }
136       if (lastUiField != null) {
137         boundClass.addAfter(field, lastUiField);
138       }
139       else {
140         boundClass.add(field);
141       }
142     }
143     catch (final IncorrectOperationException exc) {
144       if (showErrors) {
145         ApplicationManager.getApplication().invokeLater(
146           () -> Messages.showErrorDialog(
147             project,
148             UIDesignerBundle.message("error.cannot.create.field.reason", fieldName, exc.getMessage()),
149             CommonBundle.getErrorTitle()
150           )
151         );
152       }
153     }
154   }
155
156   public void run() {
157     runImpl(myEditor.getProject(), myEditor.getRootContainer(), myClass, myFieldClassName, myFieldName, true, null);
158   }
159 }