diff options
Diffstat (limited to 'java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java')
-rw-r--r-- | java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java | 402 |
1 files changed, 402 insertions, 0 deletions
diff --git a/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java new file mode 100644 index 000000000000..2afcf0fd339f --- /dev/null +++ b/java/debugger/impl/src/org/jetbrains/java/debugger/breakpoints/JavaBreakpointFiltersPanel.java @@ -0,0 +1,402 @@ +/* + * Copyright 2000-2014 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 org.jetbrains.java.debugger.breakpoints; + +import com.intellij.debugger.InstanceFilter; +import com.intellij.debugger.ui.breakpoints.EditClassFiltersDialog; +import com.intellij.debugger.ui.breakpoints.EditInstanceFiltersDialog; +import com.intellij.openapi.project.Project; +import com.intellij.openapi.ui.DialogWrapper; +import com.intellij.openapi.util.text.StringUtil; +import com.intellij.psi.PsiClass; +import com.intellij.ui.FieldPanel; +import com.intellij.ui.MultiLineTooltipUI; +import com.intellij.ui.classFilter.ClassFilter; +import com.intellij.xdebugger.XSourcePosition; +import com.intellij.xdebugger.breakpoints.XBreakpoint; +import com.intellij.xdebugger.breakpoints.ui.XBreakpointCustomPropertiesPanel; +import com.intellij.xdebugger.impl.ui.DebuggerUIUtil; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.java.debugger.breakpoints.properties.JavaBreakpointProperties; + +import javax.swing.*; +import java.awt.*; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.MouseEvent; +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +/** + * @author egor + */ +public class JavaBreakpointFiltersPanel<T extends JavaBreakpointProperties, B extends XBreakpoint<T>> extends XBreakpointCustomPropertiesPanel<B> { + private JPanel myConditionsPanel; + private JPanel myInstanceFiltersPanel; + private JCheckBox myInstanceFiltersCheckBox; + private JPanel myInstanceFiltersFieldPanel; + private JPanel myClassFiltersPanel; + private JCheckBox myClassFiltersCheckBox; + private JPanel myClassFiltersFieldPanel; + private JPanel myPassCountPanel; + private JCheckBox myPassCountCheckbox; + private JTextField myPassCountField; + + private final FieldPanel myInstanceFiltersField; + private final FieldPanel myClassFiltersField; + + private ClassFilter[] myClassFilters = ClassFilter.EMPTY_ARRAY; + private ClassFilter[] myClassExclusionFilters = ClassFilter.EMPTY_ARRAY; + private InstanceFilter[] myInstanceFilters = InstanceFilter.EMPTY_ARRAY; + protected final Project myProject; + + private PsiClass myBreakpointPsiClass; + + public JavaBreakpointFiltersPanel(Project project) { + myProject = project; + myInstanceFiltersField = new FieldPanel(new MyTextField(), "", null, + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + reloadInstanceFilters(); + EditInstanceFiltersDialog _dialog = new EditInstanceFiltersDialog(myProject); + _dialog.setFilters(myInstanceFilters); + _dialog.show(); + if (_dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + myInstanceFilters = _dialog.getFilters(); + updateInstanceFilterEditor(true); + } + } + }, + null + ); + + myClassFiltersField = new FieldPanel(new MyTextField(), "", null, + new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + reloadClassFilters(); + + com.intellij.ide.util.ClassFilter classFilter = createClassConditionFilter(); + + EditClassFiltersDialog _dialog = new EditClassFiltersDialog(myProject, classFilter); + _dialog.setFilters(myClassFilters, myClassExclusionFilters); + _dialog.show(); + if (_dialog.getExitCode() == DialogWrapper.OK_EXIT_CODE) { + myClassFilters = _dialog.getFilters(); + myClassExclusionFilters = _dialog.getExclusionFilters(); + updateClassFilterEditor(true); + } + } + }, + null + ); + + ActionListener updateListener = new ActionListener() { + @Override + public void actionPerformed(ActionEvent e) { + updateCheckboxes(); + } + }; + + myPassCountCheckbox.addActionListener(updateListener); + myInstanceFiltersCheckBox.addActionListener(updateListener); + myClassFiltersCheckBox.addActionListener(updateListener); + + ToolTipManager.sharedInstance().registerComponent(myClassFiltersField.getTextField()); + ToolTipManager.sharedInstance().registerComponent(myInstanceFiltersField.getTextField()); + + insert(myInstanceFiltersFieldPanel, myInstanceFiltersField); + insert(myClassFiltersFieldPanel, myClassFiltersField); + + DebuggerUIUtil.focusEditorOnCheck(myPassCountCheckbox, myPassCountField); + DebuggerUIUtil.focusEditorOnCheck(myInstanceFiltersCheckBox, myInstanceFiltersField.getTextField()); + DebuggerUIUtil.focusEditorOnCheck(myClassFiltersCheckBox, myClassFiltersField.getTextField()); + } + + @NotNull + @Override + public JComponent getComponent() { + return myConditionsPanel; + } + + @Override + public boolean isVisibleOnPopup(@NotNull B breakpoint) { + JavaBreakpointProperties properties = breakpoint.getProperties(); + if (properties != null) { + return properties.COUNT_FILTER_ENABLED || properties.CLASS_FILTERS_ENABLED || properties.INSTANCE_FILTERS_ENABLED; + } + return false; + } + + @Override + public void saveTo(@NotNull B breakpoint) { + JavaBreakpointProperties properties = breakpoint.getProperties(); + if (properties == null) { + return; + } + + try { + String text = myPassCountField.getText().trim(); + properties.COUNT_FILTER = !text.isEmpty() ? Integer.parseInt(text) : 0; + if (properties.COUNT_FILTER < 0) { + properties.COUNT_FILTER = 0; + } + } + catch (Exception ignored) { + } + + properties.COUNT_FILTER_ENABLED = properties.COUNT_FILTER > 0 && myPassCountCheckbox.isSelected(); + reloadInstanceFilters(); + reloadClassFilters(); + updateInstanceFilterEditor(true); + updateClassFilterEditor(true); + + properties.INSTANCE_FILTERS_ENABLED = myInstanceFiltersField.getText().length() > 0 && myInstanceFiltersCheckBox.isSelected(); + properties.CLASS_FILTERS_ENABLED = myClassFiltersField.getText().length() > 0 && myClassFiltersCheckBox.isSelected(); + properties.setClassFilters(myClassFilters); + properties.setClassExclusionFilters(myClassExclusionFilters); + properties.setInstanceFilters(myInstanceFilters); + } + + private static void insert(JPanel panel, JComponent component) { + panel.setLayout(new BorderLayout()); + panel.add(component, BorderLayout.CENTER); + } + + @Override + public void loadFrom(@NotNull B breakpoint) { + JavaBreakpointProperties properties = breakpoint.getProperties(); + if (properties != null) { + if (properties.COUNT_FILTER > 0) { + myPassCountField.setText(Integer.toString(properties.COUNT_FILTER)); + } + else { + myPassCountField.setText(""); + } + + myPassCountCheckbox.setSelected(properties.COUNT_FILTER_ENABLED); + + myInstanceFiltersCheckBox.setSelected(properties.INSTANCE_FILTERS_ENABLED); + myInstanceFiltersField.setEnabled(properties.INSTANCE_FILTERS_ENABLED); + myInstanceFiltersField.getTextField().setEditable(properties.INSTANCE_FILTERS_ENABLED); + myInstanceFilters = properties.getInstanceFilters(); + updateInstanceFilterEditor(true); + + myClassFiltersCheckBox.setSelected(properties.CLASS_FILTERS_ENABLED); + myClassFiltersField.setEnabled(properties.CLASS_FILTERS_ENABLED); + myClassFiltersField.getTextField().setEditable(properties.CLASS_FILTERS_ENABLED); + myClassFilters = properties.getClassFilters(); + myClassExclusionFilters = properties.getClassExclusionFilters(); + updateClassFilterEditor(true); + + XSourcePosition position = breakpoint.getSourcePosition(); + // TODO: need to calculate psi class + //myBreakpointPsiClass = breakpoint.getPsiClass(); + } + updateCheckboxes(); + } + + private void updateInstanceFilterEditor(boolean updateText) { + List<String> filters = new ArrayList<String>(); + for (InstanceFilter instanceFilter : myInstanceFilters) { + if (instanceFilter.isEnabled()) { + filters.add(Long.toString(instanceFilter.getId())); + } + } + if (updateText) { + myInstanceFiltersField.setText(StringUtil.join(filters, " ")); + } + + String tipText = concatWithEx(filters, " ", (int)Math.sqrt(myInstanceFilters.length) + 1, "\n"); + myInstanceFiltersField.getTextField().setToolTipText(tipText); + } + + private class MyTextField extends JTextField { + public MyTextField() { + } + + @Override + public String getToolTipText(MouseEvent event) { + reloadClassFilters(); + updateClassFilterEditor(false); + reloadInstanceFilters(); + updateInstanceFilterEditor(false); + String toolTipText = super.getToolTipText(event); + return getToolTipText().length() == 0 ? null : toolTipText; + } + + @Override + public JToolTip createToolTip() { + JToolTip toolTip = new JToolTip(){{ + setUI(new MultiLineTooltipUI()); + }}; + toolTip.setComponent(this); + return toolTip; + } + } + + private void reloadClassFilters() { + String filtersText = myClassFiltersField.getText(); + + ArrayList<ClassFilter> classFilters = new ArrayList<ClassFilter>(); + ArrayList<ClassFilter> exclusionFilters = new ArrayList<ClassFilter>(); + int startFilter = -1; + for(int i = 0; i <= filtersText.length(); i++) { + if(i < filtersText.length() && !Character.isWhitespace(filtersText.charAt(i))){ + if(startFilter == -1) { + startFilter = i; + } + } + else { + if(startFilter >=0) { + if(filtersText.charAt(startFilter) == '-') { + exclusionFilters.add(new ClassFilter(filtersText.substring(startFilter + 1, i))); + } + else { + classFilters.add(new ClassFilter(filtersText.substring(startFilter, i))); + } + startFilter = -1; + } + } + } + for (ClassFilter classFilter : myClassFilters) { + if (!classFilter.isEnabled()) { + classFilters.add(classFilter); + } + } + for (ClassFilter classFilter : myClassExclusionFilters) { + if (!classFilter.isEnabled()) { + exclusionFilters.add(classFilter); + } + } + myClassFilters = classFilters .toArray(new ClassFilter[classFilters .size()]); + myClassExclusionFilters = exclusionFilters.toArray(new ClassFilter[exclusionFilters.size()]); + } + + private void reloadInstanceFilters() { + String filtersText = myInstanceFiltersField.getText(); + + ArrayList<InstanceFilter> idxs = new ArrayList<InstanceFilter>(); + int startNumber = -1; + for(int i = 0; i <= filtersText.length(); i++) { + if(i < filtersText.length() && Character.isDigit(filtersText.charAt(i))) { + if(startNumber == -1) { + startNumber = i; + } + } + else { + if(startNumber >=0) { + idxs.add(InstanceFilter.create(filtersText.substring(startNumber, i))); + startNumber = -1; + } + } + } + for (InstanceFilter instanceFilter : myInstanceFilters) { + if (!instanceFilter.isEnabled()) { + idxs.add(instanceFilter); + } + } + myInstanceFilters = idxs.toArray(new InstanceFilter[idxs.size()]); + } + + private void updateClassFilterEditor(boolean updateText) { + List<String> filters = new ArrayList<String>(); + for (ClassFilter classFilter : myClassFilters) { + if (classFilter.isEnabled()) { + filters.add(classFilter.getPattern()); + } + } + List<String> excludeFilters = new ArrayList<String>(); + for (ClassFilter classFilter : myClassExclusionFilters) { + if (classFilter.isEnabled()) { + excludeFilters.add("-" + classFilter.getPattern()); + } + } + if (updateText) { + String editorText = StringUtil.join(filters, " "); + if(!filters.isEmpty()) { + editorText += " "; + } + editorText += StringUtil.join(excludeFilters, " "); + myClassFiltersField.setText(editorText); + } + + int width = (int)Math.sqrt(myClassExclusionFilters.length + myClassFilters.length) + 1; + String tipText = concatWithEx(filters, " ", width, "\n"); + if(!filters.isEmpty()) { + tipText += "\n"; + } + tipText += concatWithEx(excludeFilters, " ", width, "\n"); + myClassFiltersField.getTextField().setToolTipText(tipText); + } + + private static String concatWithEx(List<String> s, String concator, int N, String NthConcator) { + String result = ""; + int i = 1; + for (Iterator iterator = s.iterator(); iterator.hasNext(); i++) { + String str = (String) iterator.next(); + result += str; + if(iterator.hasNext()){ + if(i % N == 0){ + result += NthConcator; + } + else { + result += concator; + } + } + } + return result; + } + + protected com.intellij.ide.util.ClassFilter createClassConditionFilter() { + com.intellij.ide.util.ClassFilter classFilter; + if(myBreakpointPsiClass != null) { + classFilter = new com.intellij.ide.util.ClassFilter() { + @Override + public boolean isAccepted(PsiClass aClass) { + return myBreakpointPsiClass == aClass || aClass.isInheritor(myBreakpointPsiClass, true); + } + }; + } + else { + classFilter = null; + } + return classFilter; + } + + protected void updateCheckboxes() { + boolean passCountApplicable = true; + if (myInstanceFiltersCheckBox.isSelected() || myClassFiltersCheckBox.isSelected()) { + passCountApplicable = false; + } + myPassCountCheckbox.setEnabled(passCountApplicable); + + final boolean passCountSelected = myPassCountCheckbox.isSelected(); + myInstanceFiltersCheckBox.setEnabled(!passCountSelected); + myClassFiltersCheckBox.setEnabled(!passCountSelected); + + myPassCountField.setEditable(myPassCountCheckbox.isSelected()); + myPassCountField.setEnabled (myPassCountCheckbox.isSelected()); + + myInstanceFiltersField.setEnabled(myInstanceFiltersCheckBox.isSelected()); + myInstanceFiltersField.getTextField().setEditable(myInstanceFiltersCheckBox.isSelected()); + + myClassFiltersField.setEnabled(myClassFiltersCheckBox.isSelected()); + myClassFiltersField.getTextField().setEditable(myClassFiltersCheckBox.isSelected()); + } +} |