IDEA-100392 Allow file template configuration from generate popup

This commit is contained in:
Anna Kozlova
2013-08-16 20:54:07 +04:00
parent bb1cea719a
commit e0f75a31db
5 changed files with 193 additions and 41 deletions
@@ -22,17 +22,23 @@ import com.intellij.codeInsight.generation.OverrideImplementUtil;
import com.intellij.codeInsight.generation.PsiGenerationInfo;
import com.intellij.codeInsight.generation.actions.BaseGenerateAction;
import com.intellij.codeInsight.hint.HintManager;
import com.intellij.ide.fileTemplates.FileTemplateDescriptor;
import com.intellij.ide.fileTemplates.impl.AllFileTemplatesConfigurable;
import com.intellij.openapi.actionSystem.*;
import com.intellij.openapi.application.ApplicationManager;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.PopupChooserBuilder;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiTreeUtil;
import com.intellij.refactoring.util.CommonRefactoringUtil;
import com.intellij.ui.components.JBList;
import com.intellij.util.Consumer;
import com.intellij.util.Function;
import com.intellij.util.IncorrectOperationException;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -48,13 +54,46 @@ public class BaseGenerateTestSupportMethodAction extends BaseGenerateAction {
super(new MyHandler(methodKind));
}
@Nullable
@Override
public AnAction createEditTemplateAction(DataContext dataContext) {
final Project project = PlatformDataKeys.PROJECT.getData(dataContext);
final Editor editor = PlatformDataKeys.EDITOR.getData(dataContext);
final PsiFile file = LangDataKeys.PSI_FILE.getData(dataContext);
final PsiClass targetClass = editor == null || file == null ? null : getTargetClass(editor, file);
if (targetClass != null) {
final List<TestFramework> frameworks = TestIntegrationUtils.findSuitableFrameworks(targetClass);
final TestIntegrationUtils.MethodKind methodKind = ((MyHandler)getHandler()).myMethodKind;
if (!frameworks.isEmpty()) {
return new AnAction("Edit Template") {
@Override
public void actionPerformed(AnActionEvent e) {
chooseAndPerform(editor, frameworks, new Consumer<TestFramework>() {
@Override
public void consume(TestFramework framework) {
final FileTemplateDescriptor descriptor = methodKind.getFileTemplateDescriptor(framework);
if (descriptor != null) {
final String fileName = descriptor.getFileName();
AllFileTemplatesConfigurable.editCodeTemplate(FileUtil.getNameWithoutExtension(fileName), project);
} else {
HintManager.getInstance().showErrorHint(editor, "No template found for " + framework.getName() + ":" + BaseGenerateTestSupportMethodAction.this.getTemplatePresentation().getText());
}
}
});
}
};
}
}
return null;
}
@Override
protected PsiClass getTargetClass(Editor editor, PsiFile file) {
return findTargetClass(editor, file);
}
@Nullable
private static PsiClass findTargetClass(Editor editor, PsiFile file) {
private static PsiClass findTargetClass(@NotNull Editor editor, @NotNull PsiFile file) {
int offset = editor.getCaretModel().getOffset();
PsiElement element = file.findElementAt(offset);
return element == null ? null : TestIntegrationUtils.findOuterClass(element);
@@ -86,6 +125,47 @@ public class BaseGenerateTestSupportMethodAction extends BaseGenerateAction {
return true;
}
private static void chooseAndPerform(Editor editor, List<TestFramework> frameworks, final Consumer<TestFramework> consumer) {
if (frameworks.size() == 1) {
consumer.consume(frameworks.get(0));
return;
}
final JList list = new JBList(frameworks.toArray(new TestFramework[frameworks.size()]));
list.setCellRenderer(new DefaultListCellRenderer() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component result = super.getListCellRendererComponent(list, "", index, isSelected, cellHasFocus);
if (value == null) return result;
TestFramework framework = (TestFramework)value;
setIcon(framework.getIcon());
setText(framework.getName());
return result;
}
});
PopupChooserBuilder builder = new PopupChooserBuilder(list);
builder.setFilteringEnabled(new Function<Object, String>() {
@Override
public String fun(Object o) {
return ((TestFramework)o).getName();
}
});
builder
.setTitle("Choose Framework")
.setItemChoosenCallback(new Runnable() {
@Override
public void run() {
consumer.consume((TestFramework)list.getSelectedValue());
}
})
.setMovable(true)
.createPopup().showInBestPositionFor(editor);
}
private static class MyHandler implements CodeInsightActionHandler {
private TestIntegrationUtils.MethodKind myMethodKind;
@@ -98,50 +178,18 @@ public class BaseGenerateTestSupportMethodAction extends BaseGenerateAction {
final PsiClass targetClass = findTargetClass(editor, file);
final List<TestFramework> frameworks = TestIntegrationUtils.findSuitableFrameworks(targetClass);
if (frameworks.isEmpty()) return;
if (frameworks.size() == 1) {
doGenerate(editor, file, targetClass, frameworks.get(0));
return;
}
final JList list = new JBList(frameworks.toArray(new TestFramework[frameworks.size()]));
list.setCellRenderer(new DefaultListCellRenderer() {
final Consumer<TestFramework> consumer = new Consumer<TestFramework>() {
@Override
public Component getListCellRendererComponent(JList list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
Component result = super.getListCellRendererComponent(list, "", index, isSelected, cellHasFocus);
if (value == null) return result;
TestFramework framework = (TestFramework)value;
setIcon(framework.getIcon());
setText(framework.getName());
return result;
}
});
final Runnable runnable = new Runnable() {
public void run() {
TestFramework selected = (TestFramework)list.getSelectedValue();
if (selected == null) return;
doGenerate(editor, file, targetClass, selected);
public void consume(TestFramework framework) {
if (framework == null) return;
doGenerate(editor, file, targetClass, framework);
}
};
PopupChooserBuilder builder = new PopupChooserBuilder(list);
builder.setFilteringEnabled(new Function<Object, String>() {
@Override
public String fun(Object o) {
return ((TestFramework)o).getName();
}
});
builder
.setTitle("Choose Framework")
.setItemChoosenCallback(runnable)
.setMovable(true)
.createPopup().showInBestPositionFor(editor);
chooseAndPerform(editor, frameworks, consumer);
}
private void doGenerate(final Editor editor, final PsiFile file, final PsiClass targetClass, final TestFramework framework) {
if (!CommonRefactoringUtil.checkReadOnlyStatus(file)) return;
@@ -18,6 +18,8 @@ package com.intellij.codeInsight.generation.actions;
import com.intellij.codeInsight.CodeInsightActionHandler;
import com.intellij.codeInsight.actions.CodeInsightAction;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataContext;
import com.intellij.openapi.editor.Editor;
import com.intellij.openapi.project.Project;
import com.intellij.psi.*;
@@ -25,13 +27,18 @@ import com.intellij.psi.util.PsiTreeUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class BaseGenerateAction extends CodeInsightAction {
public class BaseGenerateAction extends CodeInsightAction implements GenerateActionPopupTemplateInjector {
private final CodeInsightActionHandler myHandler;
public BaseGenerateAction(CodeInsightActionHandler handler) {
myHandler = handler;
}
@Nullable
public AnAction createEditTemplateAction(DataContext dataContext) {
return null;
}
@NotNull
@Override
protected final CodeInsightActionHandler getHandler() {
@@ -0,0 +1,28 @@
/*
* Copyright 2000-2013 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.codeInsight.generation.actions;
import com.intellij.openapi.actionSystem.AnAction;
import com.intellij.openapi.actionSystem.DataContext;
import org.jetbrains.annotations.Nullable;
/**
* Generate action could provide an action to edit corresponding file template. It would appear then in the subMenu of the Generate... popup
*/
public interface GenerateActionPopupTemplateInjector {
@Nullable
AnAction createEditTemplateAction(DataContext dataContext);
}
@@ -24,6 +24,8 @@ import com.intellij.openapi.project.DumbAwareAction;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.popup.JBPopupFactory;
import com.intellij.openapi.ui.popup.ListPopup;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
public class GenerateAction extends DumbAwareAction implements PreloadableAction {
@Override
@@ -33,7 +35,7 @@ public class GenerateAction extends DumbAwareAction implements PreloadableAction
final ListPopup popup =
JBPopupFactory.getInstance().createActionGroupPopup(
CodeInsightBundle.message("generate.list.popup.title"),
getGroup(),
wrapGroup(getGroup(), dataContext),
dataContext,
JBPopupFactory.ActionSelectionAid.SPEEDSEARCH,
false);
@@ -65,8 +67,56 @@ public class GenerateAction extends DumbAwareAction implements PreloadableAction
return (DefaultActionGroup)ActionManager.getInstance().getAction(IdeActions.GROUP_GENERATE);
}
private static DefaultActionGroup wrapGroup(DefaultActionGroup actionGroup, DataContext dataContext) {
final DefaultActionGroup copy = new DefaultActionGroup();
for (final AnAction action : actionGroup.getChildren(null)) {
if (action instanceof GenerateActionPopupTemplateInjector) {
final AnAction editTemplateAction = ((GenerateActionPopupTemplateInjector)action).createEditTemplateAction(dataContext);
if (editTemplateAction != null) {
copy.add(new GenerateWrappingGroup(action, editTemplateAction));
continue;
}
}
if (action instanceof DefaultActionGroup) {
copy.add(wrapGroup((DefaultActionGroup)action, dataContext));
} else {
copy.add(action);
}
}
return copy;
}
@Override
public void preload() {
((ActionManagerImpl) ActionManager.getInstance()).preloadActionGroup(IdeActions.GROUP_GENERATE);
}
private static class GenerateWrappingGroup extends ActionGroup {
private final AnAction myAction;
private final AnAction myEditTemplateAction;
public GenerateWrappingGroup(AnAction action, AnAction editTemplateAction) {
myAction = action;
myEditTemplateAction = editTemplateAction;
copyFrom(action);
setPopup(true);
}
@Override
public boolean canBePerformed(DataContext context) {
return true;
}
@NotNull
@Override
public AnAction[] getChildren(@Nullable AnActionEvent e) {
return new AnAction[] {myEditTemplateAction};
}
@Override
public void actionPerformed(AnActionEvent e) {
myAction.actionPerformed(e);
}
}
}
@@ -28,6 +28,8 @@ import com.intellij.openapi.extensions.Extensions;
import com.intellij.openapi.options.Configurable;
import com.intellij.openapi.options.ConfigurationException;
import com.intellij.openapi.options.SearchableConfigurable;
import com.intellij.openapi.options.ShowSettingsUtil;
import com.intellij.openapi.project.Project;
import com.intellij.openapi.ui.DialogWrapper;
import com.intellij.openapi.ui.Messages;
import com.intellij.openapi.ui.Splitter;
@@ -630,4 +632,21 @@ public class AllFileTemplatesConfigurable implements SearchableConfigurable, Con
public Runnable enableSearch(String option) {
return null;
}
public static void editCodeTemplate(@NotNull final String templateId, Project project) {
final ShowSettingsUtil util = ShowSettingsUtil.getInstance();
final AllFileTemplatesConfigurable configurable = new AllFileTemplatesConfigurable();
util.editConfigurable(project, configurable, new Runnable() {
@Override
public void run() {
configurable.myTabbedPane.setSelectedIndex(ArrayUtil.indexOf(configurable.myTabs, configurable.myCodeTemplatesList));
for (FileTemplate template : configurable.myCodeTemplatesList.getTemplates()) {
if (Comparing.equal(templateId, template.getName())) {
configurable.myCodeTemplatesList.selectTemplate(template);
break;
}
}
}
});
}
}