mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
IDEA-186962 Allow user defined Async annotations
This commit is contained in:
@@ -13,6 +13,8 @@ import com.intellij.debugger.settings.ThreadsViewSettings;
|
||||
import com.intellij.debugger.ui.breakpoints.StackCapturingLineBreakpoint;
|
||||
import com.intellij.debugger.ui.tree.render.ClassRenderer;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.diagnostic.Logger;
|
||||
import com.intellij.openapi.options.ShowSettingsUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
@@ -51,7 +53,9 @@ public class StackFrameItem {
|
||||
public static final XDebuggerTreeNodeHyperlink CAPTURE_SETTINGS_OPENER = new XDebuggerTreeNodeHyperlink(" settings") {
|
||||
@Override
|
||||
public void onClick(MouseEvent event) {
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(null, CaptureConfigurable.class);
|
||||
ShowSettingsUtil.getInstance().showSettingsDialog(
|
||||
CommonDataKeys.PROJECT.getData(DataManager.getInstance().getDataContext(event.getComponent())),
|
||||
CaptureConfigurable.class);
|
||||
event.consume();
|
||||
}
|
||||
};
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<form xmlns="http://www.intellij.com/uidesigner/form/" version="1" bind-to-class="com.intellij.debugger.settings.CaptureConfigurable">
|
||||
<grid id="27dc6" binding="myPanel" layout-manager="GridLayoutManager" row-count="2" column-count="3" same-size-horizontally="false" same-size-vertically="false" hgap="-1" vgap="-1">
|
||||
<margin top="0" left="0" bottom="0" right="0"/>
|
||||
<constraints>
|
||||
<xy x="20" y="20" width="500" height="400"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="95385" class="com.intellij.ui.components.JBCheckBox" binding="myDebuggerAgent">
|
||||
<constraints>
|
||||
<grid row="0" column="0" row-span="1" col-span="1" vsize-policy="0" hsize-policy="0" anchor="0" fill="0" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/DebuggerBundle" key="label.capture.configurable.debugger.agent"/>
|
||||
</properties>
|
||||
</component>
|
||||
<hspacer id="728e7">
|
||||
<constraints>
|
||||
<grid row="0" column="2" row-span="1" col-span="1" vsize-policy="1" hsize-policy="6" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
</hspacer>
|
||||
<component id="a8e4" class="javax.swing.JButton" binding="myConfigureAnnotationsButton">
|
||||
<constraints>
|
||||
<grid row="0" column="1" row-span="1" col-span="1" vsize-policy="0" hsize-policy="3" anchor="0" fill="1" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties>
|
||||
<text resource-bundle="messages/DebuggerBundle" key="label.capture.configurable.annotations.configure"/>
|
||||
</properties>
|
||||
</component>
|
||||
<grid id="5f9b3" binding="myCapturePanel" layout-manager="BorderLayout" hgap="0" vgap="0">
|
||||
<constraints>
|
||||
<grid row="1" column="0" row-span="1" col-span="3" vsize-policy="3" hsize-policy="3" anchor="0" fill="3" indent="0" use-parent-layout="false"/>
|
||||
</constraints>
|
||||
<properties/>
|
||||
<border type="none"/>
|
||||
<children>
|
||||
<component id="99787" class="com.intellij.ui.components.JBCheckBox" binding="myCaptureVariables">
|
||||
<constraints border-constraint="South"/>
|
||||
<properties>
|
||||
<text resource-bundle="messages/DebuggerBundle" key="label.capture.configurable.capture.variables"/>
|
||||
</properties>
|
||||
</component>
|
||||
</children>
|
||||
</grid>
|
||||
</children>
|
||||
</grid>
|
||||
</form>
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.debugger.settings;
|
||||
|
||||
import com.intellij.codeInsight.AnnotationsPanel;
|
||||
import com.intellij.debugger.DebuggerBundle;
|
||||
import com.intellij.debugger.engine.JVMNameUtil;
|
||||
import com.intellij.debugger.jdi.DecompiledLocalVariable;
|
||||
@@ -22,7 +23,9 @@ import com.intellij.openapi.progress.ProcessCanceledException;
|
||||
import com.intellij.openapi.project.DumbAwareAction;
|
||||
import com.intellij.openapi.project.IndexNotReadyException;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Messages;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
import com.intellij.openapi.util.JDOMUtil;
|
||||
import com.intellij.openapi.util.registry.Registry;
|
||||
import com.intellij.openapi.util.text.StringUtil;
|
||||
@@ -37,7 +40,6 @@ import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.PlatformIcons;
|
||||
import com.intellij.util.ui.ItemRemovable;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import com.intellij.util.ui.components.BorderLayoutPanel;
|
||||
import com.intellij.util.xmlb.XmlSerializer;
|
||||
import one.util.streamex.IntStreamEx;
|
||||
import one.util.streamex.StreamEx;
|
||||
@@ -51,8 +53,10 @@ import org.jetbrains.annotations.Nullable;
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import javax.swing.table.TableColumnModel;
|
||||
import java.awt.*;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
@@ -61,10 +65,18 @@ import java.util.function.BiConsumer;
|
||||
*/
|
||||
public class CaptureConfigurable implements SearchableConfigurable {
|
||||
private static final Logger LOG = Logger.getInstance(CaptureConfigurable.class);
|
||||
private final Project myProject;
|
||||
|
||||
private JCheckBox myDebuggerAgent;
|
||||
private JButton myConfigureAnnotationsButton;
|
||||
private JPanel myCapturePanel;
|
||||
private MyTableModel myTableModel;
|
||||
private JCheckBox myCaptureVariables;
|
||||
private JPanel myPanel;
|
||||
|
||||
public CaptureConfigurable(Project project) {
|
||||
myProject = project;
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
@@ -246,19 +258,12 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
}
|
||||
});
|
||||
|
||||
BorderLayoutPanel panel = JBUI.Panels.simplePanel();
|
||||
myDebuggerAgent = new JCheckBox(DebuggerBundle.message("label.capture.configurable.debugger.agent"));
|
||||
panel.addToTop(myDebuggerAgent);
|
||||
myConfigureAnnotationsButton.addActionListener(e -> new AsyncAnnotationsDialog(myProject).show());
|
||||
|
||||
BorderLayoutPanel debuggerPanel = JBUI.Panels.simplePanel();
|
||||
debuggerPanel.setBorder(IdeBorderFactory.createTitledBorder("Breakpoints based", false));
|
||||
debuggerPanel.addToCenter(decorator.createPanel());
|
||||
myCapturePanel.setBorder(IdeBorderFactory.createTitledBorder("Breakpoints based", false));
|
||||
myCapturePanel.add(decorator.createPanel(), BorderLayout.CENTER);
|
||||
|
||||
myCaptureVariables = new JCheckBox(DebuggerBundle.message("label.capture.configurable.capture.variables"));
|
||||
debuggerPanel.addToBottom(myCaptureVariables);
|
||||
|
||||
panel.addToCenter(debuggerPanel);
|
||||
return panel;
|
||||
return myPanel;
|
||||
}
|
||||
|
||||
private StreamEx<CapturePoint> selectedCapturePoints(JBTable table) {
|
||||
@@ -506,21 +511,27 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
|
||||
static void processCaptureAnnotations(BiConsumer<Boolean, PsiModifierListOwner> consumer) {
|
||||
ApplicationManager.getApplication().assertReadAccessAllowed();
|
||||
scanPointsInt(true, consumer);
|
||||
scanPointsInt(false, consumer);
|
||||
Project project = JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables();
|
||||
DebuggerProjectSettings debuggerProjectSettings = DebuggerProjectSettings.getInstance(project);
|
||||
scanPointsInt(project, debuggerProjectSettings, true, consumer);
|
||||
scanPointsInt(project, debuggerProjectSettings, false, consumer);
|
||||
}
|
||||
|
||||
private static void scanPointsInt(boolean capture, BiConsumer<Boolean, PsiModifierListOwner> consumer) {
|
||||
private static void scanPointsInt(Project project,
|
||||
DebuggerProjectSettings debuggerProjectSettings,
|
||||
boolean capture,
|
||||
BiConsumer<Boolean, PsiModifierListOwner> consumer) {
|
||||
try {
|
||||
String annotationName = getAnnotationName(capture);
|
||||
Project project = JavaDebuggerSupport.getContextProjectForEditorFieldsInDebuggerConfigurables();
|
||||
GlobalSearchScope allScope = GlobalSearchScope.allScope(project);
|
||||
PsiClass annotationClass = JavaPsiFacade.getInstance(project).findClass(annotationName, allScope);
|
||||
if (annotationClass != null) {
|
||||
AnnotatedElementsSearch.searchElements(annotationClass, allScope, PsiMethod.class, PsiParameter.class)
|
||||
.forEach(e -> {
|
||||
consumer.accept(capture, e);
|
||||
});
|
||||
JavaPsiFacade psiFacade = JavaPsiFacade.getInstance(project);
|
||||
for (String annotationName : getAsyncAnnotations(debuggerProjectSettings, capture)) {
|
||||
PsiClass annotationClass = psiFacade.findClass(annotationName, allScope);
|
||||
if (annotationClass != null) {
|
||||
AnnotatedElementsSearch.searchElements(annotationClass, allScope, PsiMethod.class, PsiParameter.class)
|
||||
.forEach(e -> {
|
||||
consumer.accept(capture, e);
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (IndexNotReadyException | ProcessCanceledException ignore) {
|
||||
@@ -533,4 +544,57 @@ public class CaptureConfigurable implements SearchableConfigurable {
|
||||
static String getAnnotationName(boolean capture) {
|
||||
return (capture ? Async.Schedule.class : Async.Execute.class).getName().replace("$", ".");
|
||||
}
|
||||
|
||||
private static List<String> getAsyncAnnotations(DebuggerProjectSettings debuggerProjectSettings, boolean capture) {
|
||||
return StreamEx.of(capture ? debuggerProjectSettings.myAsyncScheduleAnnotations : debuggerProjectSettings.myAsyncExecuteAnnotations)
|
||||
.prepend(getAnnotationName(capture))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private class AsyncAnnotationsDialog extends DialogWrapper {
|
||||
private final AnnotationsPanel myAsyncSchedulePanel;
|
||||
private final AnnotationsPanel myAsyncExecutePanel;
|
||||
private final DebuggerProjectSettings mySettings;
|
||||
|
||||
private AsyncAnnotationsDialog(@NotNull Project project) {
|
||||
super(project, true);
|
||||
mySettings = DebuggerProjectSettings.getInstance(myProject);
|
||||
myAsyncSchedulePanel = new AnnotationsPanel(project,
|
||||
"Async Schedule",
|
||||
"",
|
||||
getAsyncAnnotations(mySettings, true),
|
||||
new String[]{getAnnotationName(true)},
|
||||
Collections.emptySet(), false, false);
|
||||
myAsyncExecutePanel = new AnnotationsPanel(project,
|
||||
"Async Execute",
|
||||
"",
|
||||
getAsyncAnnotations(mySettings, false),
|
||||
new String[]{getAnnotationName(false)},
|
||||
Collections.emptySet(), false, false);
|
||||
init();
|
||||
setTitle("Async Annotations Configuration");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected JComponent createCenterPanel() {
|
||||
final Splitter splitter = new Splitter(true);
|
||||
splitter.setFirstComponent(myAsyncSchedulePanel.getComponent());
|
||||
splitter.setSecondComponent(myAsyncExecutePanel.getComponent());
|
||||
splitter.setHonorComponentsMinimumSize(true);
|
||||
splitter.setPreferredSize(JBUI.size(300, 400));
|
||||
return splitter;
|
||||
}
|
||||
|
||||
@SuppressWarnings("SSBasedInspection")
|
||||
@Override
|
||||
protected void doOKAction() {
|
||||
mySettings.myAsyncScheduleAnnotations = StreamEx.of(myAsyncSchedulePanel.getAnnotations())
|
||||
.filter(e -> !e.equals(getAnnotationName(true)))
|
||||
.toArray(ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
mySettings.myAsyncExecuteAnnotations = StreamEx.of(myAsyncExecutePanel.getAnnotations())
|
||||
.filter(e -> !e.equals(getAnnotationName(false)))
|
||||
.toArray(ArrayUtil.EMPTY_STRING_ARRAY);
|
||||
super.doOKAction();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.debugger.settings;
|
||||
|
||||
import com.intellij.openapi.components.PersistentStateComponent;
|
||||
import com.intellij.openapi.components.ServiceManager;
|
||||
import com.intellij.openapi.components.State;
|
||||
import com.intellij.openapi.components.Storage;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.util.ArrayUtil;
|
||||
import com.intellij.util.xmlb.XmlSerializerUtil;
|
||||
import com.intellij.util.xmlb.annotations.XCollection;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
/**
|
||||
* @author egor
|
||||
*/
|
||||
@State(name = "DebuggerSettings", storages = @Storage("debugger.xml"))
|
||||
public class DebuggerProjectSettings implements PersistentStateComponent<DebuggerProjectSettings> {
|
||||
@XCollection(propertyElementName = "async-schedule-annotations", elementName = "annotation", valueAttributeName = "name")
|
||||
public String[] myAsyncScheduleAnnotations = ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
|
||||
@XCollection(propertyElementName = "async-execute-annotations", elementName = "annotation", valueAttributeName = "name")
|
||||
public String[] myAsyncExecuteAnnotations = ArrayUtil.EMPTY_STRING_ARRAY;
|
||||
|
||||
public static DebuggerProjectSettings getInstance(@NotNull Project project) {
|
||||
return ServiceManager.getService(project, DebuggerProjectSettings.class);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public DebuggerProjectSettings getState() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void loadState(@NotNull DebuggerProjectSettings state) {
|
||||
XmlSerializerUtil.copyBean(state, this);
|
||||
}
|
||||
}
|
||||
@@ -45,8 +45,6 @@ public class JavaDebuggerSettings extends XDebuggerSettings<Element> {
|
||||
case HOTSWAP:
|
||||
return singletonList(SimpleConfigurable.create("reference.idesettings.debugger.hotswap", OptionsBundle.message("options.java.display.name"),
|
||||
JavaHotSwapConfigurableUi.class, DebuggerSettings::getInstance));
|
||||
case ROOT:
|
||||
return singletonList(new CaptureConfigurable());
|
||||
}
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,225 @@
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.ide.util.TreeClassChooser;
|
||||
import com.intellij.ide.util.TreeClassChooserFactory;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.ui.EmptyIcon;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.DefaultTableColumnModel;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableColumn;
|
||||
import java.awt.*;
|
||||
import java.util.List;
|
||||
import java.util.*;
|
||||
|
||||
public class AnnotationsPanel {
|
||||
private final Project myProject;
|
||||
private String myDefaultAnnotation;
|
||||
private final Set<String> myDefaultAnnotations;
|
||||
private final JBTable myTable;
|
||||
private final JPanel myComponent;
|
||||
protected final DefaultTableModel myTableModel;
|
||||
|
||||
public AnnotationsPanel(Project project,
|
||||
String name,
|
||||
String defaultAnnotation,
|
||||
List<String> annotations,
|
||||
String[] defaultAnnotations,
|
||||
Set<String> checkedAnnotations,
|
||||
boolean showInstrumentationOptions,
|
||||
boolean showDefaultActions) {
|
||||
myProject = project;
|
||||
myDefaultAnnotation = defaultAnnotation;
|
||||
myDefaultAnnotations = new HashSet<>(Arrays.asList(defaultAnnotations));
|
||||
myTableModel = new DefaultTableModel() {
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
return column == 1;
|
||||
}
|
||||
};
|
||||
myTableModel.setColumnCount(showInstrumentationOptions ? 2 : 1);
|
||||
for (String annotation : annotations) {
|
||||
addRow(annotation, checkedAnnotations.contains(annotation));
|
||||
}
|
||||
|
||||
DefaultTableColumnModel columnModel = new DefaultTableColumnModel();
|
||||
columnModel.addColumn(new TableColumn(0, 100, new ColoredTableCellRenderer() {
|
||||
@Override
|
||||
public void acquireState(JTable table, boolean isSelected, boolean hasFocus, int row, int column) {
|
||||
super.acquireState(table, isSelected, false, row, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeCellRenderer(JTable table,
|
||||
Object value,
|
||||
boolean selected,
|
||||
boolean hasFocus,
|
||||
int row,
|
||||
int column) {
|
||||
append((String)value, SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
if (value.equals(myDefaultAnnotation)) {
|
||||
setIcon(AllIcons.Diff.CurrentLine);
|
||||
}
|
||||
else {
|
||||
setIcon(EmptyIcon.ICON_16);
|
||||
}
|
||||
}
|
||||
}, null));
|
||||
|
||||
myTable = new JBTable(myTableModel, columnModel);
|
||||
|
||||
if (showInstrumentationOptions) {
|
||||
columnModel.getColumn(0).setHeaderValue("Annotation");
|
||||
|
||||
TableColumn checkColumn = new TableColumn(1, 100, new BooleanTableCellRenderer(), new BooleanTableCellEditor());
|
||||
columnModel.addColumn(checkColumn);
|
||||
checkColumn.setHeaderValue(" Instrument ");
|
||||
|
||||
TableCellRenderer defaultRenderer = myTable.getTableHeader().getDefaultRenderer();
|
||||
|
||||
TableCellRenderer headerRenderer = new TableCellRenderer() {
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
boolean hasFocus,
|
||||
int row,
|
||||
int column) {
|
||||
Component component = defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
if (component instanceof JComponent) {
|
||||
((JComponent)component)
|
||||
.setToolTipText(column == 1 ? "Add runtime assertions for notnull-annotated methods and parameters" : null);
|
||||
}
|
||||
return component;
|
||||
}
|
||||
};
|
||||
myTable.getTableHeader().setDefaultRenderer(headerRenderer);
|
||||
checkColumn.setHeaderRenderer(headerRenderer);
|
||||
checkColumn.sizeWidthToFit();
|
||||
}
|
||||
|
||||
final AnActionButton selectButton =
|
||||
new AnActionButton("Select annotation used for code generation", AllIcons.Actions.Checked) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
String selectedValue = getSelectedAnnotation();
|
||||
if (selectedValue == null) return;
|
||||
myDefaultAnnotation = selectedValue;
|
||||
|
||||
// to show the new default value in the ui
|
||||
myTableModel.fireTableRowsUpdated(myTable.getSelectedRow(), myTable.getSelectedRow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateButton(AnActionEvent e) {
|
||||
String selectedValue = getSelectedAnnotation();
|
||||
e.getPresentation().setEnabled(selectedValue != null && !selectedValue.equals(myDefaultAnnotation));
|
||||
}
|
||||
};
|
||||
|
||||
final ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTable).disableUpDownActions()
|
||||
.setAddAction(b -> chooseAnnotation(name))
|
||||
.setRemoveAction(new AnActionButtonRunnable() {
|
||||
@Override
|
||||
public void run(AnActionButton anActionButton) {
|
||||
String selectedValue = getSelectedAnnotation();
|
||||
if (selectedValue == null) return;
|
||||
if (myDefaultAnnotation.equals(selectedValue)) myDefaultAnnotation = (String)myTable.getValueAt(0, 0);
|
||||
|
||||
myTableModel.removeRow(myTable.getSelectedRow());
|
||||
}
|
||||
})
|
||||
.setRemoveActionUpdater(e -> !myDefaultAnnotations.contains(getSelectedAnnotation()));
|
||||
if (showDefaultActions) {
|
||||
toolbarDecorator.addExtraAction(selectButton);
|
||||
}
|
||||
final JPanel panel = toolbarDecorator.createPanel();
|
||||
myComponent = new JPanel(new BorderLayout());
|
||||
myComponent.setBorder(IdeBorderFactory.createTitledBorder(name + " annotations", false, JBUI.insetsTop(10)));
|
||||
myComponent.add(panel);
|
||||
myComponent.setPreferredSize(new JBDimension(myComponent.getPreferredSize().width, 200));
|
||||
|
||||
myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
myTable.setRowSelectionAllowed(true);
|
||||
myTable.setShowGrid(false);
|
||||
|
||||
selectAnnotation(myDefaultAnnotation);
|
||||
}
|
||||
|
||||
private void addRow(String annotation, boolean checked) {
|
||||
myTableModel.addRow(new Object[]{annotation, checked});
|
||||
}
|
||||
|
||||
private Integer selectAnnotation(String annotation) {
|
||||
for (int i = 0; i < myTable.getRowCount(); i++) {
|
||||
if (annotation.equals(myTable.getValueAt(i, 0))) {
|
||||
myTable.setRowSelectionInterval(i, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getSelectedAnnotation() {
|
||||
int selectedRow = myTable.getSelectedRow();
|
||||
return selectedRow < 0 ? null : (String)myTable.getValueAt(selectedRow, 0);
|
||||
}
|
||||
|
||||
private void chooseAnnotation(String title) {
|
||||
final TreeClassChooser chooser = TreeClassChooserFactory.getInstance(myProject)
|
||||
.createNoInnerClassesScopeChooser("Choose " + title + " annotation", GlobalSearchScope.allScope(myProject), new ClassFilter() {
|
||||
@Override
|
||||
public boolean isAccepted(PsiClass aClass) {
|
||||
return aClass.isAnnotationType();
|
||||
}
|
||||
}, null);
|
||||
chooser.showDialog();
|
||||
final PsiClass selected = chooser.getSelected();
|
||||
if (selected == null) {
|
||||
return;
|
||||
}
|
||||
final String qualifiedName = selected.getQualifiedName();
|
||||
if (selectAnnotation(qualifiedName) == null) {
|
||||
addRow(qualifiedName, false);
|
||||
}
|
||||
}
|
||||
|
||||
public JComponent getComponent() {
|
||||
return myComponent;
|
||||
}
|
||||
|
||||
String getDefaultAnnotation() {
|
||||
return myDefaultAnnotation;
|
||||
}
|
||||
|
||||
public String[] getAnnotations() {
|
||||
int size = myTable.getRowCount();
|
||||
String[] result = new String[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
result[i] = (String)myTable.getValueAt(i, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
List<String> getCheckedAnnotations() {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (int i = 0; i < myTable.getRowCount(); i++) {
|
||||
if (Boolean.TRUE.equals(myTable.getValueAt(i, 1))) {
|
||||
result.add((String)myTable.getValueAt(i, 0));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
@@ -1,50 +1,22 @@
|
||||
// Copyright 2000-2017 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.
|
||||
// Copyright 2000-2018 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.
|
||||
package com.intellij.codeInsight;
|
||||
|
||||
import com.intellij.codeInspection.InspectionsBundle;
|
||||
import com.intellij.icons.AllIcons;
|
||||
import com.intellij.ide.DataManager;
|
||||
import com.intellij.ide.util.ClassFilter;
|
||||
import com.intellij.ide.util.TreeClassChooser;
|
||||
import com.intellij.ide.util.TreeClassChooserFactory;
|
||||
import com.intellij.openapi.actionSystem.AnActionEvent;
|
||||
import com.intellij.openapi.actionSystem.CommonDataKeys;
|
||||
import com.intellij.openapi.project.Project;
|
||||
import com.intellij.openapi.project.ProjectManager;
|
||||
import com.intellij.openapi.ui.DialogWrapper;
|
||||
import com.intellij.openapi.ui.Splitter;
|
||||
import com.intellij.psi.PsiClass;
|
||||
import com.intellij.psi.search.GlobalSearchScope;
|
||||
import com.intellij.ui.*;
|
||||
import com.intellij.ui.table.JBTable;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.intellij.util.ui.EmptyIcon;
|
||||
import com.intellij.util.ui.JBDimension;
|
||||
import com.intellij.util.ui.JBUI;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.swing.*;
|
||||
import javax.swing.table.DefaultTableColumnModel;
|
||||
import javax.swing.table.DefaultTableModel;
|
||||
import javax.swing.table.TableCellRenderer;
|
||||
import javax.swing.table.TableColumn;
|
||||
import java.awt.*;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.ActionListener;
|
||||
import java.util.*;
|
||||
import java.util.List;
|
||||
import java.util.Collections;
|
||||
|
||||
public class NullableNotNullDialog extends DialogWrapper {
|
||||
private final Project myProject;
|
||||
@@ -62,14 +34,16 @@ public class NullableNotNullDialog extends DialogWrapper {
|
||||
myShowInstrumentationOptions = showInstrumentationOptions;
|
||||
|
||||
NullableNotNullManager manager = NullableNotNullManager.getInstance(myProject);
|
||||
myNullablePanel = new AnnotationsPanel("Nullable",
|
||||
myNullablePanel = new AnnotationsPanel(project,
|
||||
"Nullable",
|
||||
manager.getDefaultNullable(),
|
||||
manager.getNullables(), NullableNotNullManager.DEFAULT_NULLABLES,
|
||||
Collections.emptySet(), false);
|
||||
myNotNullPanel = new AnnotationsPanel("NotNull",
|
||||
Collections.emptySet(), false, true);
|
||||
myNotNullPanel = new AnnotationsPanel(project,
|
||||
"NotNull",
|
||||
manager.getDefaultNotNull(),
|
||||
manager.getNotNulls(), NullableNotNullManager.DEFAULT_NOT_NULLS,
|
||||
ContainerUtil.newHashSet(manager.getInstrumentedNotNulls()), showInstrumentationOptions);
|
||||
ContainerUtil.newHashSet(manager.getInstrumentedNotNulls()), showInstrumentationOptions, true);
|
||||
|
||||
init();
|
||||
setTitle("Nullable/NotNull Configuration");
|
||||
@@ -132,192 +106,4 @@ public class NullableNotNullDialog extends DialogWrapper {
|
||||
|
||||
super.doOKAction();
|
||||
}
|
||||
|
||||
private class AnnotationsPanel {
|
||||
private String myDefaultAnnotation;
|
||||
private final Set<String> myDefaultAnnotations;
|
||||
private final JBTable myTable;
|
||||
private final JPanel myComponent;
|
||||
private final DefaultTableModel myTableModel;
|
||||
|
||||
private AnnotationsPanel(String name, String defaultAnnotation, List<String> annotations, String[] defaultAnnotations, Set<String> checkedAnnotations, boolean showInstrumentationOptions) {
|
||||
myDefaultAnnotation = defaultAnnotation;
|
||||
myDefaultAnnotations = new HashSet<>(Arrays.asList(defaultAnnotations));
|
||||
myTableModel = new DefaultTableModel() {
|
||||
@Override
|
||||
public boolean isCellEditable(int row, int column) {
|
||||
return column == 1;
|
||||
}
|
||||
};
|
||||
myTableModel.setColumnCount(showInstrumentationOptions ? 2 : 1);
|
||||
for (String annotation : annotations) {
|
||||
addRow(annotation, checkedAnnotations.contains(annotation));
|
||||
}
|
||||
|
||||
DefaultTableColumnModel columnModel = new DefaultTableColumnModel();
|
||||
columnModel.addColumn(new TableColumn(0, 100, new ColoredTableCellRenderer() {
|
||||
@Override
|
||||
public void acquireState(JTable table, boolean isSelected, boolean hasFocus, int row, int column) {
|
||||
super.acquireState(table, isSelected, false, row, column);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void customizeCellRenderer(JTable table,
|
||||
Object value,
|
||||
boolean selected,
|
||||
boolean hasFocus,
|
||||
int row,
|
||||
int column) {
|
||||
append((String)value, SimpleTextAttributes.REGULAR_ATTRIBUTES);
|
||||
if (value.equals(myDefaultAnnotation)) {
|
||||
setIcon(AllIcons.Diff.CurrentLine);
|
||||
} else {
|
||||
setIcon(EmptyIcon.ICON_16);
|
||||
}
|
||||
}
|
||||
}, null));
|
||||
|
||||
myTable = new JBTable(myTableModel, columnModel);
|
||||
|
||||
if (showInstrumentationOptions) {
|
||||
columnModel.getColumn(0).setHeaderValue("Annotation");
|
||||
|
||||
TableColumn checkColumn = new TableColumn(1, 100, new BooleanTableCellRenderer(), new BooleanTableCellEditor());
|
||||
columnModel.addColumn(checkColumn);
|
||||
checkColumn.setHeaderValue(" Instrument ");
|
||||
|
||||
TableCellRenderer defaultRenderer = myTable.getTableHeader().getDefaultRenderer();
|
||||
|
||||
TableCellRenderer headerRenderer = new TableCellRenderer() {
|
||||
@Override
|
||||
public Component getTableCellRendererComponent(JTable table,
|
||||
Object value,
|
||||
boolean isSelected,
|
||||
boolean hasFocus,
|
||||
int row,
|
||||
int column) {
|
||||
Component component = defaultRenderer.getTableCellRendererComponent(table, value, isSelected, hasFocus, row, column);
|
||||
if (component instanceof JComponent) {
|
||||
((JComponent)component)
|
||||
.setToolTipText(column == 1 ? "Add runtime assertions for notnull-annotated methods and parameters" : null);
|
||||
}
|
||||
return component;
|
||||
}
|
||||
};
|
||||
myTable.getTableHeader().setDefaultRenderer(headerRenderer);
|
||||
checkColumn.setHeaderRenderer(headerRenderer);
|
||||
checkColumn.sizeWidthToFit();
|
||||
}
|
||||
|
||||
final AnActionButton selectButton =
|
||||
new AnActionButton("Select annotation used for code generation", AllIcons.Actions.Checked) {
|
||||
@Override
|
||||
public void actionPerformed(AnActionEvent e) {
|
||||
String selectedValue = getSelectedAnnotation();
|
||||
if (selectedValue == null) return;
|
||||
myDefaultAnnotation = selectedValue;
|
||||
|
||||
// to show the new default value in the ui
|
||||
myTableModel.fireTableRowsUpdated(myTable.getSelectedRow(), myTable.getSelectedRow());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void updateButton(AnActionEvent e) {
|
||||
String selectedValue = getSelectedAnnotation();
|
||||
e.getPresentation().setEnabled(selectedValue != null && !selectedValue.equals(myDefaultAnnotation));
|
||||
}
|
||||
};
|
||||
|
||||
final ToolbarDecorator toolbarDecorator = ToolbarDecorator.createDecorator(myTable).disableUpDownActions()
|
||||
.setAddAction(b -> chooseAnnotation(name))
|
||||
.setRemoveAction(new AnActionButtonRunnable() {
|
||||
@Override
|
||||
public void run(AnActionButton anActionButton) {
|
||||
String selectedValue = getSelectedAnnotation();
|
||||
if (selectedValue == null) return;
|
||||
if (myDefaultAnnotation.equals(selectedValue)) myDefaultAnnotation = (String)myTable.getValueAt(0, 0);
|
||||
|
||||
myTableModel.removeRow(myTable.getSelectedRow());
|
||||
}
|
||||
})
|
||||
.setRemoveActionUpdater(e -> !myDefaultAnnotations.contains(getSelectedAnnotation()))
|
||||
.addExtraAction(selectButton);
|
||||
final JPanel panel = toolbarDecorator.createPanel();
|
||||
myComponent = new JPanel(new BorderLayout());
|
||||
myComponent.setBorder(IdeBorderFactory.createTitledBorder(name + " annotations", false, JBUI.insetsTop(10)));
|
||||
myComponent.add(panel);
|
||||
myComponent.setPreferredSize(new JBDimension(myComponent.getPreferredSize().width, 200));
|
||||
|
||||
myTable.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
|
||||
myTable.setRowSelectionAllowed(true);
|
||||
myTable.setShowGrid(false);
|
||||
|
||||
selectAnnotation(myDefaultAnnotation);
|
||||
}
|
||||
|
||||
private void addRow(String annotation, boolean checked) {
|
||||
myTableModel.addRow(new Object[]{annotation, checked});
|
||||
}
|
||||
|
||||
private Integer selectAnnotation(String annotation) {
|
||||
for (int i = 0; i < myTable.getRowCount(); i++) {
|
||||
if (annotation.equals(myTable.getValueAt(i, 0))) {
|
||||
myTable.setRowSelectionInterval(i, i);
|
||||
return i;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String getSelectedAnnotation() {
|
||||
int selectedRow = myTable.getSelectedRow();
|
||||
return selectedRow <0 ? null : (String)myTable.getValueAt(selectedRow, 0);
|
||||
}
|
||||
|
||||
private void chooseAnnotation(String title) {
|
||||
final TreeClassChooser chooser = TreeClassChooserFactory.getInstance(myProject)
|
||||
.createNoInnerClassesScopeChooser("Choose " + title + " annotation", GlobalSearchScope.allScope(myProject), new ClassFilter() {
|
||||
@Override
|
||||
public boolean isAccepted(PsiClass aClass) {
|
||||
return aClass.isAnnotationType();
|
||||
}
|
||||
}, null);
|
||||
chooser.showDialog();
|
||||
final PsiClass selected = chooser.getSelected();
|
||||
if (selected == null) {
|
||||
return;
|
||||
}
|
||||
final String qualifiedName = selected.getQualifiedName();
|
||||
if (selectAnnotation(qualifiedName) == null) {
|
||||
addRow(qualifiedName, false);
|
||||
}
|
||||
}
|
||||
|
||||
JComponent getComponent() {
|
||||
return myComponent;
|
||||
}
|
||||
|
||||
String getDefaultAnnotation() {
|
||||
return myDefaultAnnotation;
|
||||
}
|
||||
|
||||
String[] getAnnotations() {
|
||||
int size = myTable.getRowCount();
|
||||
String[] result = new String[size];
|
||||
for (int i = 0; i < size; i++) {
|
||||
result[i] = (String)myTable.getValueAt(i, 0);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
List<String> getCheckedAnnotations() {
|
||||
List<String> result = new ArrayList<>();
|
||||
for (int i = 0; i < myTable.getRowCount(); i++) {
|
||||
if (Boolean.TRUE.equals(myTable.getValueAt(i, 1))) {
|
||||
result.add((String)myTable.getValueAt(i, 0));
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -262,6 +262,7 @@ label.threads.view.configurable.show.stack.frames.for.synthetic.methods=Show sta
|
||||
label.threads.view.configurable.show.thread.groups=Show thread &groups
|
||||
label.capture.configurable.capture.variables=Capture local variables (may greatly slow down the execution)
|
||||
label.capture.configurable.debugger.agent=Instrumenting agent (requires debugger restart)
|
||||
label.capture.configurable.annotations.configure=Configure annotations...
|
||||
threads.view.configurable.display.name=Customize Threads View
|
||||
user.renderers.configurable.display.name=Java Type Renderers
|
||||
async.stacktraces.configurable.display.name=Async Stack Traces
|
||||
|
||||
@@ -281,6 +281,9 @@
|
||||
|
||||
<xdebugger.debuggerSupport implementation="com.intellij.debugger.ui.JavaDebuggerSupport"/>
|
||||
<xdebugger.settings implementation="com.intellij.debugger.settings.JavaDebuggerSettings"/>
|
||||
|
||||
<projectConfigurable parentId="project.propDebugger" instance="com.intellij.debugger.settings.CaptureConfigurable"/>
|
||||
|
||||
<xdebugger.localAttachDebuggerProvider implementation="com.intellij.debugger.engine.JavaAttachDebuggerProvider"/>
|
||||
|
||||
<xdebugger.breakpointType implementation="com.intellij.debugger.ui.breakpoints.JavaMethodBreakpointType"/>
|
||||
|
||||
@@ -149,6 +149,7 @@
|
||||
<applicationService serviceImplementation="com.intellij.debugger.settings.NodeRendererSettings"/>
|
||||
<applicationService serviceImplementation="com.intellij.debugger.settings.ViewsGeneralSettings"/>
|
||||
<applicationService serviceImplementation="com.intellij.debugger.settings.DebuggerSettings"/>
|
||||
<projectService serviceImplementation="com.intellij.debugger.settings.DebuggerProjectSettings"/>
|
||||
<applicationService serviceImplementation="com.intellij.debugger.settings.ThreadsViewSettings"/>
|
||||
|
||||
<applicationService serviceInterface="com.intellij.packaging.elements.PackagingElementFactory"
|
||||
|
||||
Reference in New Issue
Block a user