Cleanup: NotNull/Nullable
[idea/community.git] / java / java-impl / src / com / intellij / ide / hierarchy / method / OverrideImplementMethodAction.java
1 // Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package com.intellij.ide.hierarchy.method;
3
4 import com.intellij.codeInsight.generation.OverrideImplementUtil;
5 import com.intellij.ide.hierarchy.HierarchyNodeDescriptor;
6 import com.intellij.ide.hierarchy.MethodHierarchyBrowserBase;
7 import com.intellij.openapi.actionSystem.*;
8 import com.intellij.openapi.application.ApplicationManager;
9 import com.intellij.openapi.command.CommandProcessor;
10 import com.intellij.openapi.diagnostic.Logger;
11 import com.intellij.openapi.project.Project;
12 import com.intellij.openapi.ui.Messages;
13 import com.intellij.openapi.vfs.ReadonlyStatusHandler;
14 import com.intellij.openapi.vfs.VirtualFile;
15 import com.intellij.openapi.wm.ToolWindowManager;
16 import com.intellij.psi.*;
17 import com.intellij.psi.util.MethodSignature;
18 import com.intellij.util.IncorrectOperationException;
19 import org.jetbrains.annotations.NotNull;
20
21 import java.util.ArrayList;
22 import java.util.Collection;
23 import java.util.List;
24
25 abstract class OverrideImplementMethodAction extends AnAction {
26   private static final Logger LOG = Logger.getInstance("#com.intellij.ide.hierarchy.method.OverrideImplementMethodAction");
27
28   @Override
29   public final void actionPerformed(@NotNull final AnActionEvent event) {
30     final DataContext dataContext = event.getDataContext();
31     final MethodHierarchyBrowser methodHierarchyBrowser = (MethodHierarchyBrowser)MethodHierarchyBrowserBase.DATA_KEY.getData(dataContext);
32     if (methodHierarchyBrowser == null) return;
33     final Project project = CommonDataKeys.PROJECT.getData(dataContext);
34     if (project == null) return;
35
36     final String commandName = event.getPresentation().getText();
37     ApplicationManager.getApplication().runWriteAction(() -> CommandProcessor.getInstance().executeCommand(project, () -> {
38
39       try{
40         final HierarchyNodeDescriptor[] selectedDescriptors = methodHierarchyBrowser.getSelectedDescriptors();
41         if (selectedDescriptors.length > 0) {
42           final List<VirtualFile> files = new ArrayList<>(selectedDescriptors.length);
43           for (HierarchyNodeDescriptor selectedDescriptor : selectedDescriptors) {
44             final PsiFile containingFile = ((MethodHierarchyNodeDescriptor)selectedDescriptor).getPsiClass().getContainingFile();
45             if (containingFile != null) {
46               final VirtualFile vFile = containingFile.getVirtualFile();
47               if (vFile != null) {
48                 files.add(vFile);
49               }
50             }
51           }
52           final ReadonlyStatusHandler.OperationStatus status = ReadonlyStatusHandler.getInstance(project).ensureFilesWritable(files);
53           if (!status.hasReadonlyFiles()) {
54             for (HierarchyNodeDescriptor selectedDescriptor : selectedDescriptors) {
55               final PsiElement aClass = ((MethodHierarchyNodeDescriptor)selectedDescriptor).getPsiClass();
56               if (aClass instanceof PsiClass) {
57                 OverrideImplementUtil.overrideOrImplement((PsiClass)aClass, methodHierarchyBrowser.getBaseMethod());
58               }
59             }
60             ToolWindowManager.getInstance(project).activateEditorComponent();
61           }
62           else {
63             ApplicationManager.getApplication().invokeLater(
64               () -> Messages.showErrorDialog(project, status.getReadonlyFilesMessage(), commandName));
65           }
66         }
67       }
68       catch(IncorrectOperationException e){
69         LOG.error(e);
70       }
71     }, commandName, null));
72   }
73
74   @Override
75   public final void update(@NotNull final AnActionEvent e) {
76     final Presentation presentation = e.getPresentation();
77     final DataContext dataContext = e.getDataContext();
78
79     final MethodHierarchyBrowser methodHierarchyBrowser = (MethodHierarchyBrowser)MethodHierarchyBrowserBase.DATA_KEY.getData(dataContext);
80     if (methodHierarchyBrowser == null) {
81       presentation.setEnabledAndVisible(false);
82       return;
83     }
84     final Project project = CommonDataKeys.PROJECT.getData(dataContext);
85     if (project == null) {
86       presentation.setEnabledAndVisible(false);
87       return;
88     }
89
90     final HierarchyNodeDescriptor[] selectedDescriptors = methodHierarchyBrowser.getSelectedDescriptors();
91     int toImplement = 0;
92     int toOverride = 0;
93
94     for (final HierarchyNodeDescriptor descriptor : selectedDescriptors) {
95       if (canImplementOverride((MethodHierarchyNodeDescriptor)descriptor, methodHierarchyBrowser, true)) {
96         if (toOverride > 0) {
97           // no mixed actions allowed
98           presentation.setEnabledAndVisible(false);
99           return;
100         }
101         toImplement++;
102       }
103       else if (canImplementOverride((MethodHierarchyNodeDescriptor)descriptor, methodHierarchyBrowser, false)) {
104         if (toImplement > 0) {
105           // no mixed actions allowed
106           presentation.setEnabledAndVisible(false);
107           return;
108         }
109         toOverride++;
110       }
111       else {
112         // no action is applicable to this node
113         presentation.setEnabledAndVisible(false);
114         return;
115       }
116     }
117
118     presentation.setVisible(true);
119
120     update(presentation, toImplement, toOverride);
121   }
122
123   protected abstract void update(Presentation presentation, int toImplement, int toOverride);
124
125   private static boolean canImplementOverride(final MethodHierarchyNodeDescriptor descriptor, final MethodHierarchyBrowser methodHierarchyBrowser, final boolean toImplement) {
126     final PsiElement psiElement = descriptor.getPsiClass();
127     if (!(psiElement instanceof PsiClass)) return false;
128     final PsiClass psiClass = (PsiClass)psiElement;
129     if (psiClass instanceof PsiSyntheticClass) return false;
130     final PsiMethod baseMethod = methodHierarchyBrowser.getBaseMethod();
131     if (baseMethod == null) return false;
132     final MethodSignature signature = baseMethod.getSignature(PsiSubstitutor.EMPTY);
133
134     Collection<MethodSignature> allOriginalSignatures = toImplement
135                                                         ? OverrideImplementUtil.getMethodSignaturesToImplement(psiClass)
136                                                         : OverrideImplementUtil.getMethodSignaturesToOverride(psiClass);
137     for (final MethodSignature originalSignature : allOriginalSignatures) {
138       if (originalSignature.equals(signature)) {
139         return true;
140       }
141     }
142
143     return false;
144   }
145 }