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
.codeInsight
.generation
;
18 import com
.intellij
.codeInsight
.CodeInsightActionHandler
;
19 import com
.intellij
.codeInsight
.template
.Template
;
20 import com
.intellij
.codeInsight
.template
.TemplateEditingAdapter
;
21 import com
.intellij
.codeInsight
.template
.TemplateManager
;
22 import com
.intellij
.ide
.util
.MemberChooser
;
23 import com
.intellij
.openapi
.application
.ApplicationManager
;
24 import com
.intellij
.openapi
.application
.Result
;
25 import com
.intellij
.openapi
.command
.WriteCommandAction
;
26 import com
.intellij
.openapi
.diagnostic
.Logger
;
27 import com
.intellij
.openapi
.editor
.Editor
;
28 import com
.intellij
.openapi
.editor
.LogicalPosition
;
29 import com
.intellij
.openapi
.editor
.ScrollType
;
30 import com
.intellij
.openapi
.editor
.Document
;
31 import com
.intellij
.openapi
.editor
.actions
.EnterAction
;
32 import com
.intellij
.openapi
.fileEditor
.FileDocumentManager
;
33 import com
.intellij
.openapi
.project
.Project
;
34 import com
.intellij
.openapi
.util
.TextRange
;
35 import com
.intellij
.openapi
.util
.text
.StringUtil
;
36 import com
.intellij
.psi
.PsiClass
;
37 import com
.intellij
.psi
.PsiDocumentManager
;
38 import com
.intellij
.psi
.PsiElement
;
39 import com
.intellij
.psi
.PsiFile
;
40 import com
.intellij
.util
.IncorrectOperationException
;
41 import org
.jetbrains
.annotations
.NotNull
;
42 import org
.jetbrains
.annotations
.Nullable
;
44 import java
.util
.ArrayList
;
45 import java
.util
.Arrays
;
46 import java
.util
.List
;
51 public abstract class GenerateMembersHandlerBase
implements CodeInsightActionHandler
{
52 private static final Logger LOG
= Logger
.getInstance("#com.intellij.codeInsight.generation.GenerateMembersHandlerBase");
54 private final String myChooserTitle
;
55 protected boolean myToCopyJavaDoc
= false;
57 public GenerateMembersHandlerBase(String chooserTitle
) {
58 myChooserTitle
= chooserTitle
;
61 public final void invoke(@NotNull final Project project
, @NotNull final Editor editor
, @NotNull PsiFile file
) {
62 if (!FileDocumentManager
.getInstance().requestWriting(editor
.getDocument(), project
)) {
65 final PsiClass aClass
= OverrideImplementUtil
.getContextClass(project
, editor
, file
, false);
66 if (aClass
== null || aClass
.isInterface()) return; //?
67 LOG
.assertTrue(aClass
.isValid());
68 LOG
.assertTrue(aClass
.getContainingFile() != null);
71 final ClassMember
[] members
= chooseOriginalMembers(aClass
, project
);
72 if (members
== null) return;
74 ApplicationManager
.getApplication().runWriteAction(new Runnable() {
76 doGenerate(project
, editor
, aClass
, members
);
85 protected void cleanup() {
88 private void doGenerate(final Project project
, final Editor editor
, PsiClass aClass
, ClassMember
[] members
) {
89 int offset
= editor
.getCaretModel().getOffset();
91 int col
= editor
.getCaretModel().getLogicalPosition().column
;
92 int line
= editor
.getCaretModel().getLogicalPosition().line
;
93 final Document document
= editor
.getDocument();
94 int lineStartOffset
= document
.getLineStartOffset(line
);
95 CharSequence docText
= document
.getCharsSequence();
96 String textBeforeCaret
= docText
.subSequence(lineStartOffset
, offset
).toString();
97 final String afterCaret
= docText
.subSequence(offset
, document
.getLineEndOffset(line
)).toString();
98 if (textBeforeCaret
.trim().length() > 0 && StringUtil
.isEmptyOrSpaces(afterCaret
) && !editor
.getSelectionModel().hasSelection()) {
99 EnterAction
.insertNewLineAtCaret(editor
);
100 PsiDocumentManager
.getInstance(project
).commitDocument(document
);
101 offset
= editor
.getCaretModel().getOffset();
102 col
= editor
.getCaretModel().getLogicalPosition().column
;
103 line
= editor
.getCaretModel().getLogicalPosition().line
;
106 editor
.getCaretModel().moveToLogicalPosition(new LogicalPosition(0, 0));
108 List
<?
extends GenerationInfo
> newMembers
;
110 List
<?
extends GenerationInfo
> prototypes
= generateMemberPrototypes(aClass
, members
);
111 newMembers
= GenerateMembersUtil
.insertMembersAtOffset(aClass
.getContainingFile(), offset
, prototypes
);
113 catch(IncorrectOperationException e
){
117 if (newMembers
.isEmpty()) return;
119 editor
.getCaretModel().moveToLogicalPosition(new LogicalPosition(line
, col
));
121 final ArrayList
<TemplateGenerationInfo
> templates
= new ArrayList
<TemplateGenerationInfo
>();
122 for (GenerationInfo member
: newMembers
) {
123 if (member
instanceof TemplateGenerationInfo
) {
124 templates
.add((TemplateGenerationInfo
) member
);
128 if (!templates
.isEmpty()){
129 PsiDocumentManager
.getInstance(project
).doPostponedOperationsAndUnblockDocument(document
);
130 runTemplates(project
, editor
, templates
, 0);
132 else if (!newMembers
.isEmpty()){
133 GenerateMembersUtil
.positionCaret(editor
, newMembers
.get(0).getPsiMember(), false);
137 private static void runTemplates(final Project myProject
, final Editor editor
, final List
<TemplateGenerationInfo
> templates
, final int index
) {
138 TemplateGenerationInfo info
= templates
.get(index
);
139 final Template template
= info
.getTemplate();
141 final PsiElement element
= info
.getPsiMember();
142 final TextRange range
= element
.getTextRange();
143 editor
.getDocument().deleteString(range
.getStartOffset(), range
.getEndOffset());
144 int offset
= range
.getStartOffset();
145 editor
.getCaretModel().moveToOffset(offset
);
146 editor
.getScrollingModel().scrollToCaret(ScrollType
.CENTER
);
147 TemplateManager
.getInstance(myProject
).startTemplate(editor
, template
, new TemplateEditingAdapter() {
148 public void templateFinished(Template template
) {
149 if (index
+ 1 < templates
.size()){
150 ApplicationManager
.getApplication().invokeLater(new Runnable() {
152 new WriteCommandAction(myProject
) {
153 protected void run(Result result
) throws Throwable
{
154 runTemplates(myProject
, editor
, templates
, index
+ 1);
166 protected ClassMember
[] chooseOriginalMembers(PsiClass aClass
, Project project
) {
167 ClassMember
[] allMembers
= getAllOriginalMembers(aClass
);
168 return chooseMembers(allMembers
, false, false, project
);
172 protected final ClassMember
[] chooseMembers(ClassMember
[] members
, boolean allowEmptySelection
, boolean copyJavadocCheckbox
, Project project
) {
173 MemberChooser
<ClassMember
> chooser
= new MemberChooser
<ClassMember
>(members
, allowEmptySelection
, true, project
);
174 chooser
.setTitle(myChooserTitle
);
175 chooser
.setCopyJavadocVisible(copyJavadocCheckbox
);
177 myToCopyJavaDoc
= chooser
.isCopyJavadoc();
178 final List
<ClassMember
> list
= chooser
.getSelectedElements();
179 return list
== null ?
null : list
.toArray(new ClassMember
[list
.size()]);
183 protected List
<?
extends GenerationInfo
> generateMemberPrototypes(PsiClass aClass
, ClassMember
[] members
) throws IncorrectOperationException
{
184 ArrayList
<GenerationInfo
> array
= new ArrayList
<GenerationInfo
>();
185 for (ClassMember member
: members
) {
186 GenerationInfo
[] prototypes
= generateMemberPrototypes(aClass
, member
);
187 if (prototypes
!= null) {
188 array
.addAll(Arrays
.asList(prototypes
));
194 protected abstract ClassMember
[] getAllOriginalMembers(PsiClass aClass
);
196 protected abstract GenerationInfo
[] generateMemberPrototypes(PsiClass aClass
, ClassMember originalMember
) throws IncorrectOperationException
;
198 public boolean startInWriteAction() {