| /* |
| * 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.breakpoints.XBreakpointBase; |
| 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.isCOUNT_FILTER_ENABLED() || properties.isCLASS_FILTERS_ENABLED() || properties.isINSTANCE_FILTERS_ENABLED(); |
| } |
| return false; |
| } |
| |
| @Override |
| public void saveTo(@NotNull B breakpoint) { |
| JavaBreakpointProperties properties = breakpoint.getProperties(); |
| if (properties == null) { |
| return; |
| } |
| |
| boolean changed = false; |
| try { |
| String text = myPassCountField.getText().trim(); |
| int filter = !text.isEmpty() ? Integer.parseInt(text) : 0; |
| if (filter < 0) filter = 0; |
| changed = properties.setCOUNT_FILTER(filter); |
| } |
| catch (Exception ignored) { |
| } |
| |
| changed = properties.setCOUNT_FILTER_ENABLED(properties.getCOUNT_FILTER() > 0 && myPassCountCheckbox.isSelected()) || changed; |
| reloadInstanceFilters(); |
| reloadClassFilters(); |
| updateInstanceFilterEditor(true); |
| updateClassFilterEditor(true); |
| |
| changed = properties.setINSTANCE_FILTERS_ENABLED(myInstanceFiltersField.getText().length() > 0 && myInstanceFiltersCheckBox.isSelected()) || changed; |
| changed = properties.setCLASS_FILTERS_ENABLED(myClassFiltersField.getText().length() > 0 && myClassFiltersCheckBox.isSelected()) || changed; |
| changed = properties.setClassFilters(myClassFilters) || changed; |
| changed = properties.setClassExclusionFilters(myClassExclusionFilters) || changed; |
| changed = properties.setInstanceFilters(myInstanceFilters) || changed; |
| if (changed) { |
| ((XBreakpointBase)breakpoint).fireBreakpointChanged(); |
| } |
| } |
| |
| 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.getCOUNT_FILTER() > 0) { |
| myPassCountField.setText(Integer.toString(properties.getCOUNT_FILTER())); |
| } |
| else { |
| myPassCountField.setText(""); |
| } |
| |
| myPassCountCheckbox.setSelected(properties.isCOUNT_FILTER_ENABLED()); |
| |
| myInstanceFiltersCheckBox.setSelected(properties.isINSTANCE_FILTERS_ENABLED()); |
| myInstanceFiltersField.setEnabled(properties.isINSTANCE_FILTERS_ENABLED()); |
| myInstanceFiltersField.getTextField().setEditable(properties.isINSTANCE_FILTERS_ENABLED()); |
| myInstanceFilters = properties.getInstanceFilters(); |
| updateInstanceFilterEditor(true); |
| |
| myClassFiltersCheckBox.setSelected(properties.isCLASS_FILTERS_ENABLED()); |
| myClassFiltersField.setEnabled(properties.isCLASS_FILTERS_ENABLED()); |
| myClassFiltersField.getTextField().setEditable(properties.isCLASS_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()); |
| } |
| } |