diff --git a/java/debugger/impl/src/com/intellij/debugger/memory/utils/StackFrameItem.java b/java/debugger/impl/src/com/intellij/debugger/memory/utils/StackFrameItem.java
index eaba0af42dac..4be5231c3970 100644
--- a/java/debugger/impl/src/com/intellij/debugger/memory/utils/StackFrameItem.java
+++ b/java/debugger/impl/src/com/intellij/debugger/memory/utils/StackFrameItem.java
@@ -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();
}
};
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CaptureConfigurable.form b/java/debugger/impl/src/com/intellij/debugger/settings/CaptureConfigurable.form
new file mode 100644
index 000000000000..9e4c513abbb5
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/CaptureConfigurable.form
@@ -0,0 +1,49 @@
+
+
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/CaptureConfigurable.java b/java/debugger/impl/src/com/intellij/debugger/settings/CaptureConfigurable.java
index a1807ff28997..6c9173e919b6 100644
--- a/java/debugger/impl/src/com/intellij/debugger/settings/CaptureConfigurable.java
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/CaptureConfigurable.java
@@ -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 selectedCapturePoints(JBTable table) {
@@ -506,21 +511,27 @@ public class CaptureConfigurable implements SearchableConfigurable {
static void processCaptureAnnotations(BiConsumer 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 consumer) {
+ private static void scanPointsInt(Project project,
+ DebuggerProjectSettings debuggerProjectSettings,
+ boolean capture,
+ BiConsumer 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 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();
+ }
+ }
}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerProjectSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerProjectSettings.java
new file mode 100644
index 000000000000..66e3f9567a4f
--- /dev/null
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/DebuggerProjectSettings.java
@@ -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 {
+ @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);
+ }
+}
diff --git a/java/debugger/impl/src/com/intellij/debugger/settings/JavaDebuggerSettings.java b/java/debugger/impl/src/com/intellij/debugger/settings/JavaDebuggerSettings.java
index 59736e351320..ddee8defc915 100644
--- a/java/debugger/impl/src/com/intellij/debugger/settings/JavaDebuggerSettings.java
+++ b/java/debugger/impl/src/com/intellij/debugger/settings/JavaDebuggerSettings.java
@@ -45,8 +45,6 @@ public class JavaDebuggerSettings extends XDebuggerSettings {
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();
}
diff --git a/java/openapi/src/com/intellij/codeInsight/AnnotationsPanel.java b/java/openapi/src/com/intellij/codeInsight/AnnotationsPanel.java
new file mode 100644
index 000000000000..ef5803c2aca0
--- /dev/null
+++ b/java/openapi/src/com/intellij/codeInsight/AnnotationsPanel.java
@@ -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 myDefaultAnnotations;
+ private final JBTable myTable;
+ private final JPanel myComponent;
+ protected final DefaultTableModel myTableModel;
+
+ public AnnotationsPanel(Project project,
+ String name,
+ String defaultAnnotation,
+ List annotations,
+ String[] defaultAnnotations,
+ Set 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 getCheckedAnnotations() {
+ List 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;
+ }
+}
\ No newline at end of file
diff --git a/java/openapi/src/com/intellij/codeInsight/NullableNotNullDialog.java b/java/openapi/src/com/intellij/codeInsight/NullableNotNullDialog.java
index 63b3f1929f6a..5e0ad4032f1b 100644
--- a/java/openapi/src/com/intellij/codeInsight/NullableNotNullDialog.java
+++ b/java/openapi/src/com/intellij/codeInsight/NullableNotNullDialog.java
@@ -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 myDefaultAnnotations;
- private final JBTable myTable;
- private final JPanel myComponent;
- private final DefaultTableModel myTableModel;
-
- private AnnotationsPanel(String name, String defaultAnnotation, List annotations, String[] defaultAnnotations, Set 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 getCheckedAnnotations() {
- List 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;
- }
- }
}
diff --git a/resources-en/src/messages/DebuggerBundle.properties b/resources-en/src/messages/DebuggerBundle.properties
index f3aceaa78524..a95b01bc547f 100644
--- a/resources-en/src/messages/DebuggerBundle.properties
+++ b/resources-en/src/messages/DebuggerBundle.properties
@@ -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
diff --git a/resources/src/META-INF/JavaIdePlugin.xml b/resources/src/META-INF/JavaIdePlugin.xml
index 665b41dad986..8610c29e0fc7 100644
--- a/resources/src/META-INF/JavaIdePlugin.xml
+++ b/resources/src/META-INF/JavaIdePlugin.xml
@@ -281,6 +281,9 @@
+
+
+
diff --git a/resources/src/idea/RichPlatformPlugin.xml b/resources/src/idea/RichPlatformPlugin.xml
index 74447e0104db..ea2c6a199ecb 100644
--- a/resources/src/idea/RichPlatformPlugin.xml
+++ b/resources/src/idea/RichPlatformPlugin.xml
@@ -149,6 +149,7 @@
+