diff --git a/api.debugger.jpda/nbproject/project.xml b/api.debugger.jpda/nbproject/project.xml --- a/api.debugger.jpda/nbproject/project.xml +++ b/api.debugger.jpda/nbproject/project.xml @@ -55,7 +55,7 @@ 1 - 1.16 + 1.34 diff --git a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDABreakpoint.java b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDABreakpoint.java --- a/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDABreakpoint.java +++ b/api.debugger.jpda/src/org/netbeans/api/debugger/jpda/JPDABreakpoint.java @@ -251,6 +251,11 @@ synchronized JPDADebugger getSession() { return session; } + + @Override + public boolean canHaveDependentBreakpoints() { + return true; + } /** * Adds a JPDABreakpointListener. diff --git a/api.debugger/apichanges.xml b/api.debugger/apichanges.xml --- a/api.debugger/apichanges.xml +++ b/api.debugger/apichanges.xml @@ -463,6 +463,31 @@ + + + Added a possibility to enable/disable other breakpoints when one is hit. + + + + + + Four methods are added to the Breakpoint class, that allow to + get or set a set of breakpoints, that are enabled or disabled when + the breakpoint is hit. One test method is provided, which determines + if the dependent breakpoints are supported by the implementation. +

+ Added methods:
+ Breakpoint.canHaveDependentBreakpoints(), + Breakpoint.getBreakpointsToEnable(), + Breakpoint.setBreakpointsToEnable(), + Breakpoint.getBreakpointsToDisable(), + Breakpoint.setBreakpointsToDisable(). +

+
+ + +
+ diff --git a/api.debugger/manifest.mf b/api.debugger/manifest.mf --- a/api.debugger/manifest.mf +++ b/api.debugger/manifest.mf @@ -1,5 +1,5 @@ Manifest-Version: 1.0 OpenIDE-Module: org.netbeans.api.debugger/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/Bundle.properties -OpenIDE-Module-Specification-Version: 1.33 +OpenIDE-Module-Specification-Version: 1.34 OpenIDE-Module-Layer: org/netbeans/api/debugger/layer.xml diff --git a/api.debugger/nbproject/project.xml b/api.debugger/nbproject/project.xml --- a/api.debugger/nbproject/project.xml +++ b/api.debugger/nbproject/project.xml @@ -50,6 +50,15 @@ org.netbeans.api.debugger + org.netbeans.api.annotations.common + + + + 1 + 1.11 + + + org.netbeans.modules.projectapi diff --git a/api.debugger/src/org/netbeans/api/debugger/Breakpoint.java b/api.debugger/src/org/netbeans/api/debugger/Breakpoint.java --- a/api.debugger/src/org/netbeans/api/debugger/Breakpoint.java +++ b/api.debugger/src/org/netbeans/api/debugger/Breakpoint.java @@ -46,6 +46,9 @@ import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; +import java.util.Collections; +import java.util.Set; +import org.netbeans.api.annotations.common.NonNull; import org.netbeans.api.project.Project; import org.openide.filesystems.FileObject; @@ -86,6 +89,8 @@ private String validityMessage; private int hitCountFilter; private HIT_COUNT_FILTERING_STYLE hitCountFilteringStyle; + private volatile Set breakpointsToEnable = Collections.EMPTY_SET; + private volatile Set breakpointsToDisable = Collections.EMPTY_SET; { pcs = new PropertyChangeSupport (this); } @@ -230,6 +235,93 @@ return null; } + /** + * Determines if the breakpoint supports dependent breakpoints. + * If true, get/setBreakpointsToEnable/Disable methods can be used to get + * or set dependent breakpoints. + * If false, the methods throw an UnsupportedOperationException. + * @return true if the dependent breakpoints are supported, + * false otherwise. + * @since 1.34 + */ + public boolean canHaveDependentBreakpoints() { + return false; + } + + /** + * Get the set of breakpoints that will be enabled after this breakpoint + * is hit. + *

+ * Not all breakpoint implementations honor dependent breakpoints. + * Use {@link #canHaveDependentBreakpoints()} to determine if the operation is supported. + * @return The set of breakpoints. + * @throws UnsupportedOperationException if the breakpoint does not support + * dependent breakpoints - see {@link #canHaveDependentBreakpoints()}. + * @since 1.34 + */ + @NonNull + public Set getBreakpointsToEnable() { + if (!canHaveDependentBreakpoints()) { + throw new UnsupportedOperationException("Cannot have dependent breakpoints."); // NOI18N + } + return breakpointsToEnable; + } + + /** + * Get the set of breakpoints that will be disabled after this breakpoint + * is hit. + *

+ * Not all breakpoint implementations honor dependent breakpoints. + * Use {@link #canHaveDependentBreakpoints()} to determine if the operation is supported. + * @throws UnsupportedOperationException if the breakpoint does not support + * dependent breakpoints - see {@link #canHaveDependentBreakpoints()}. + * @return The set of breakpoints. + * @since 1.34 + */ + @NonNull + public Set getBreakpointsToDisable() { + if (!canHaveDependentBreakpoints()) { + throw new UnsupportedOperationException("Cannot have dependent breakpoints."); // NOI18N + } + return breakpointsToDisable; + } + + /** + * Set the set of breakpoints that will be enabled after this breakpoint + * is hit. + *

+ * Not all breakpoint implementations honor dependent breakpoints. + * Use {@link #canHaveDependentBreakpoints()} to determine if the operation is supported. + * @param breakpointsToEnable The set of breakpoints. + * @throws UnsupportedOperationException if the breakpoint does not support + * dependent breakpoints - see {@link #canHaveDependentBreakpoints()}. + * @since 1.34 + */ + public void setBreakpointsToEnable(@NonNull Set breakpointsToEnable) { + if (!canHaveDependentBreakpoints()) { + throw new UnsupportedOperationException("Cannot have dependent breakpoints."); // NOI18N + } + this.breakpointsToEnable = breakpointsToEnable; + } + + /** + * Set the set of breakpoints that will be disabled after this breakpoint + * is hit. + *

+ * Not all breakpoint implementations honor dependent breakpoints. + * Use {@link #canHaveDependentBreakpoints()} to determine if the operation is supported. + * @param breakpointsToEnable The set of breakpoints. + * @throws UnsupportedOperationException if the breakpoint does not support + * dependent breakpoints - see {@link #canHaveDependentBreakpoints()}. + * @since 1.34 + */ + public void setBreakpointsToDisable(@NonNull Set breakpointsToDisable) { + if (!canHaveDependentBreakpoints()) { + throw new UnsupportedOperationException("Cannot have dependent breakpoints."); // NOI18N + } + this.breakpointsToDisable = breakpointsToDisable; + } + /** * Add a listener to property changes. * diff --git a/debugger.jpda.ui/nbproject/project.xml b/debugger.jpda.ui/nbproject/project.xml --- a/debugger.jpda.ui/nbproject/project.xml +++ b/debugger.jpda.ui/nbproject/project.xml @@ -151,6 +151,15 @@ + org.netbeans.modules.projectapi + + + + 1 + 1.39 + + + org.netbeans.spi.debugger.ui diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ActionsPanel.form b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ActionsPanel.form --- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ActionsPanel.form +++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ActionsPanel.form @@ -29,23 +29,6 @@ - - - - - - - - - - - - - - - - - @@ -89,26 +72,6 @@ - - - - - - - - - - - - - - - - - - - - @@ -133,5 +96,117 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ActionsPanel.java b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ActionsPanel.java --- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ActionsPanel.java +++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/ActionsPanel.java @@ -45,10 +45,27 @@ package org.netbeans.modules.debugger.jpda.ui.breakpoints; import java.awt.Dimension; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; import java.util.ResourceBundle; +import java.util.Set; +import java.util.TreeSet; import java.util.prefs.Preferences; +import org.netbeans.api.debugger.Breakpoint; +import org.netbeans.api.debugger.DebuggerManager; import org.netbeans.api.debugger.jpda.JPDABreakpoint; +import org.netbeans.api.project.Project; +import org.netbeans.modules.debugger.jpda.breakpoints.BreakpointsFromGroup; +import org.netbeans.modules.debugger.jpda.breakpoints.BreakpointsFromGroup.TestGroupProperties; +import org.netbeans.modules.debugger.jpda.ui.breakpoints.BreakpointsExpandableGroup.FileItem; +import org.netbeans.modules.debugger.jpda.ui.breakpoints.BreakpointsExpandableGroup.FilesGroup; +import org.netbeans.modules.debugger.jpda.ui.breakpoints.BreakpointsExpandableGroup.ProjectItem; +import org.netbeans.modules.debugger.jpda.ui.breakpoints.BreakpointsExpandableGroup.ProjectsGroup; +import org.netbeans.modules.debugger.jpda.ui.breakpoints.BreakpointsExpandableGroup.TypeItem; +import org.netbeans.modules.debugger.jpda.ui.breakpoints.BreakpointsExpandableGroup.TypesGroup; +import org.openide.filesystems.FileObject; import org.openide.util.NbBundle; import org.openide.util.NbPreferences; @@ -64,6 +81,7 @@ private int defaultSuspendAction; private int checkedSuspendAction; private Preferences preferences = NbPreferences.forModule(JPDABreakpoint.class).node("debugging"); // NOI18N + private static final Object NONE_BREAKPOINT_GROUP = new NoneBreakpointGroup(); /** Creates new form LineBreakpointPanel */ public ActionsPanel (JPDABreakpoint b) { @@ -105,6 +123,22 @@ 30*tfPrintText.getFontMetrics(tfPrintText.getFont()).charWidth('W'), tfPrintText.getPreferredSize().height)); tfPrintText.setCaretPosition(0); + + enableGroupCheckBox.setVisible(false); + disableGroupCheckBox.setVisible(false); + Object[] groups = getGroups(); + Set breakpointsToEnable = breakpoint.getBreakpointsToEnable(); + Set breakpointsToDisable = breakpoint.getBreakpointsToDisable(); + BreakpointsFromGroup bfgToEnable = null; + BreakpointsFromGroup bfgToDisable = null; + if (breakpointsToEnable instanceof BreakpointsFromGroup) { + bfgToEnable = (BreakpointsFromGroup) breakpointsToEnable; + } + if (breakpointsToDisable instanceof BreakpointsFromGroup) { + bfgToDisable = (BreakpointsFromGroup) breakpointsToDisable; + } + fillGroups((OutlineComboBox) enableGroupComboBox, groups, bfgToEnable); + fillGroups((OutlineComboBox) disableGroupComboBox, groups, bfgToDisable); } /** This method is called from within the constructor to @@ -116,28 +150,23 @@ private void initComponents() { java.awt.GridBagConstraints gridBagConstraints; - tfPrintText = new javax.swing.JTextField(); jLabel1 = new javax.swing.JLabel(); cbSuspend = new javax.swing.JComboBox(); - jLabel2 = new javax.swing.JLabel(); checkBoxPanel = new javax.swing.JPanel(); defaultActionCheckBox = new javax.swing.JCheckBox(); + enableGroupCheckBox = new javax.swing.JCheckBox(); + enableGroupLabel = new javax.swing.JLabel(); + enableGroupComboBox = new OutlineComboBox(); + disableGroupCheckBox = new javax.swing.JCheckBox(); + disableGroupLabel = new javax.swing.JLabel(); + disableGroupComboBox = new OutlineComboBox(); + jLabel2 = new javax.swing.JLabel(); + tfPrintText = new javax.swing.JTextField(); java.util.ResourceBundle bundle = java.util.ResourceBundle.getBundle("org/netbeans/modules/debugger/jpda/ui/breakpoints/Bundle"); // NOI18N setBorder(javax.swing.BorderFactory.createTitledBorder(bundle.getString("L_Actions_Panel_BorderTitle"))); // NOI18N setLayout(new java.awt.GridBagLayout()); - tfPrintText.setToolTipText(bundle.getString("TTT_TF_Actions_Panel_Print_Text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 1; - gridBagConstraints.gridy = 1; - gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; - gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; - gridBagConstraints.weightx = 1.0; - gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); - add(tfPrintText, gridBagConstraints); - tfPrintText.getAccessibleContext().setAccessibleDescription(bundle.getString("ACSD_TF_Actions_Panel_Print_Text")); // NOI18N - jLabel1.setLabelFor(cbSuspend); org.openide.awt.Mnemonics.setLocalizedText(jLabel1, bundle.getString("L_Actions_Panel_Suspend")); // NOI18N gridBagConstraints = new java.awt.GridBagConstraints(); @@ -162,16 +191,6 @@ add(cbSuspend, gridBagConstraints); cbSuspend.getAccessibleContext().setAccessibleDescription(bundle.getString("ASCD_CB_Actions_Panel_Suspend")); // NOI18N - jLabel2.setLabelFor(tfPrintText); - org.openide.awt.Mnemonics.setLocalizedText(jLabel2, bundle.getString("L_Actions_Panel_Print_Text")); // NOI18N - gridBagConstraints = new java.awt.GridBagConstraints(); - gridBagConstraints.gridx = 0; - gridBagConstraints.gridy = 1; - gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; - gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); - add(jLabel2, gridBagConstraints); - jLabel2.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ActionsPanel.class, "ACSD_PrintText")); // NOI18N - checkBoxPanel.setLayout(new java.awt.GridBagLayout()); org.openide.awt.Mnemonics.setLocalizedText(defaultActionCheckBox, "jCheckBox1"); @@ -194,6 +213,75 @@ gridBagConstraints.insets = new java.awt.Insets(0, 10, 0, 10); add(checkBoxPanel, gridBagConstraints); + org.openide.awt.Mnemonics.setLocalizedText(enableGroupCheckBox, org.openide.util.NbBundle.getMessage(ActionsPanel.class, "MSG_EnableGroup")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridy = 1; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + add(enableGroupCheckBox, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(enableGroupLabel, org.openide.util.NbBundle.getMessage(ActionsPanel.class, "MSG_EnableGroup")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 1; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0); + add(enableGroupLabel, gridBagConstraints); + + enableGroupComboBox.setEditable(true); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 1; + gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); + add(enableGroupComboBox, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(disableGroupCheckBox, org.openide.util.NbBundle.getMessage(ActionsPanel.class, "MSG_DisableGroup")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridy = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + add(disableGroupCheckBox, gridBagConstraints); + + org.openide.awt.Mnemonics.setLocalizedText(disableGroupLabel, org.openide.util.NbBundle.getMessage(ActionsPanel.class, "MSG_DisableGroup")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 2; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.insets = new java.awt.Insets(0, 3, 0, 0); + add(disableGroupLabel, gridBagConstraints); + + disableGroupComboBox.setEditable(true); + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 2; + gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(0, 3, 3, 3); + add(disableGroupComboBox, gridBagConstraints); + + jLabel2.setLabelFor(tfPrintText); + org.openide.awt.Mnemonics.setLocalizedText(jLabel2, bundle.getString("L_Actions_Panel_Print_Text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 0; + gridBagConstraints.gridy = 3; + gridBagConstraints.anchor = java.awt.GridBagConstraints.WEST; + gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); + add(jLabel2, gridBagConstraints); + jLabel2.getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ActionsPanel.class, "ACSD_PrintText")); // NOI18N + + tfPrintText.setToolTipText(bundle.getString("TTT_TF_Actions_Panel_Print_Text")); // NOI18N + gridBagConstraints = new java.awt.GridBagConstraints(); + gridBagConstraints.gridx = 1; + gridBagConstraints.gridy = 3; + gridBagConstraints.gridwidth = java.awt.GridBagConstraints.REMAINDER; + gridBagConstraints.fill = java.awt.GridBagConstraints.HORIZONTAL; + gridBagConstraints.weightx = 1.0; + gridBagConstraints.insets = new java.awt.Insets(3, 3, 3, 3); + add(tfPrintText, gridBagConstraints); + tfPrintText.getAccessibleContext().setAccessibleDescription(bundle.getString("ACSD_TF_Actions_Panel_Print_Text")); // NOI18N + getAccessibleContext().setAccessibleDescription(org.openide.util.NbBundle.getMessage(ActionsPanel.class, "ACSD_Actions")); // NOI18N }// //GEN-END:initComponents @@ -236,6 +324,183 @@ if (checkedSuspendAction != defaultSuspendAction) { preferences.putInt(DEFAULT_SUSPEND_ACTION, checkedSuspendAction); } + Object breakpointsToEnableGroup = enableGroupComboBox.getSelectedItem(); + breakpoint.setBreakpointsToEnable(createBreakpointsSet(breakpointsToEnableGroup)); + Object breakpointsToDisableGroup = disableGroupComboBox.getSelectedItem(); + breakpoint.setBreakpointsToDisable(createBreakpointsSet(breakpointsToDisableGroup)); + /* + if (breakpointsToDisableGroup == null || breakpointsToDisableGroup == NONE_BREAKPOINT_GROUP) { + breakpoint.setBreakpointsToDisable(Collections.EMPTY_SET); + } else { + TestGroupProperties tgp = createTestProperties(breakpointsToDisableGroup); + if (tgp != null) { + breakpoint.setBreakpointsToDisable(new BreakpointsFromGroup(tgp)); + } else { + String customGroup = (String) breakpointsToDisableGroup; + customGroup = customGroup.trim(); + if (!customGroup.isEmpty()) { + breakpoint.setBreakpointsToDisable(new BreakpointsFromGroup(customGroup)); + } else { + breakpoint.setBreakpointsToDisable(Collections.EMPTY_SET); + } + } + } + */ + } + + private static Set createBreakpointsSet(Object selectedGroup) { + if (selectedGroup == null || selectedGroup == NONE_BREAKPOINT_GROUP) { + return Collections.EMPTY_SET; + } else { + TestGroupProperties tgp = createTestProperties(selectedGroup); + if (tgp != null) { + return new BreakpointsFromGroup(tgp); + } else { + String customGroup = (String) selectedGroup; + customGroup = customGroup.trim(); + if (!customGroup.isEmpty()) { + return new BreakpointsFromGroup(customGroup); + } else { + return Collections.EMPTY_SET; + } + } + } + } + + /* + private static Object getItem(JComboBox cb, BreakpointsFromGroup bfg) { + String groupName = bfg.getGroupName(); + if (groupName != null) { + return groupName; + } + TestGroupProperties testProperties = bfg.getTestProperties(); + + FileObject fo = testProperties.getFileObject(); + if (fo != null) { + + } + } + */ + + private static TestGroupProperties createTestProperties(Object group) { + if (group instanceof FileItem) { + return new TestGroupProperties(((FileItem) group).getFileObject()); + } + if (group instanceof ProjectItem) { + return new TestGroupProperties(((ProjectItem) group).getProject()); + } + if (group instanceof TypeItem) { + return new TestGroupProperties(((TypeItem) group).getType()); + } + return null; + } + + private void fillGroupNames(OutlineComboBox cb, Object[] groupNames) { + //DefaultComboBoxModel cbm = new DefaultComboBoxModel(groupNames); + cb.setItems(groupNames); + cb.setSelectedIndex(0); + } + + private Object[] fillGroups(OutlineComboBox cb, Object[] groups, BreakpointsFromGroup groupToSelect) { + int index = groups.length - 3; + FilesGroup fg = new FilesGroup(); + ProjectsGroup pg = new ProjectsGroup(); + TypesGroup tg = new TypesGroup(); + groups[index++] = fg; + groups[index++] = pg; + groups[index++] = tg; + cb.setItems(groups); + if (groupToSelect == null) { + cb.setSelectedIndex(0); + } else { + String groupName = groupToSelect.getGroupName(); + if (groupName != null) { + cb.setSelectedItem(groupName); + } else { + TestGroupProperties tgp = groupToSelect.getTestGroupProperties(); + FileObject fo = tgp.getFileObject(); + if (fo != null) { + FileItem[] items = fg.getItems(); + for (FileItem fi : items) { + if (fo.equals(fi.getFileObject())) { + cb.getModel().setSelectedItem(fg); // To expand it and fill the items + cb.setSelectedItem(fi); + break; + } + } + } + Project project = tgp.getProject(); + if (project != null) { + ProjectItem[] items = pg.getItems(); + for (ProjectItem pi : items) { + if (project.equals(pi.getProject())) { + cb.getModel().setSelectedItem(pg); // To expand it and fill the items + cb.setSelectedItem(pi); + break; + } + } + } + String type = tgp.getType(); + if (type != null) { + TypeItem[] items = tg.getItems(); + for (TypeItem ti : items) { + if (type.equals(ti.getType())) { + cb.getModel().setSelectedItem(tg); // To expand it and fill the items + cb.setSelectedItem(ti); + break; + } + } + } + } + } + return groups; + } + + private static String[] getGroupNames() { + Set groupNamesSorted = new TreeSet(); + Breakpoint[] bs = DebuggerManager.getDebuggerManager ().getBreakpoints (); + for (int i = 0; i < bs.length; i++) { + String gn = bs[i].getGroupName(); + groupNamesSorted.add(gn); + } + groupNamesSorted.remove(""); // Remove the defalt group + List groupNames = new ArrayList(groupNamesSorted); + groupNames.add(0, NbBundle.getMessage(ActionsPanel.class, "LBL_NoneBreakpointGroup")); + return groupNames.toArray(new String[0]); + } + + private static Object[] getGroups() { + Set groupNamesSorted = new TreeSet(); + Breakpoint[] bs = DebuggerManager.getDebuggerManager ().getBreakpoints (); + for (int i = 0; i < bs.length; i++) { + String gn = bs[i].getGroupName(); + groupNamesSorted.add(gn); + } + groupNamesSorted.remove(""); // Remove the defalt group + Object[] groups = new Object[1 + groupNamesSorted.size() + 3]; // 3 expandable groups + groups[0] = NONE_BREAKPOINT_GROUP; + int i = 1; + for (String gn : groupNamesSorted) { + groups[i++] = gn; + } + return groups; + } + + private static final class NoneBreakpointGroup { + + @Override + public String toString() { + return NbBundle.getMessage(ActionsPanel.class, "LBL_NoneBreakpointGroup"); + } + + public static Object valueOf(String newString) { + if (newString.isEmpty() || NbBundle.getMessage(ActionsPanel.class, "LBL_NoneBreakpointGroup").equals(newString)) { + return NONE_BREAKPOINT_GROUP; + } else { + return newString; + } + } + } @@ -243,6 +508,12 @@ private javax.swing.JComboBox cbSuspend; private javax.swing.JPanel checkBoxPanel; private javax.swing.JCheckBox defaultActionCheckBox; + private javax.swing.JCheckBox disableGroupCheckBox; + private javax.swing.JComboBox disableGroupComboBox; + private javax.swing.JLabel disableGroupLabel; + private javax.swing.JCheckBox enableGroupCheckBox; + private javax.swing.JComboBox enableGroupComboBox; + private javax.swing.JLabel enableGroupLabel; private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JTextField tfPrintText; diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/BreakpointsExpandableGroup.java b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/BreakpointsExpandableGroup.java new file mode 100644 --- /dev/null +++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/BreakpointsExpandableGroup.java @@ -0,0 +1,360 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.debugger.jpda.ui.breakpoints; + +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Set; +import java.util.TreeSet; +import org.netbeans.api.debugger.Breakpoint; +import org.netbeans.api.debugger.Breakpoint.GroupProperties; +import org.netbeans.api.debugger.DebuggerManager; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.api.project.ProjectUtils; +import org.netbeans.modules.debugger.jpda.ui.breakpoints.OutlineComboBox.PopupMenuItem; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileStateInvalidException; +import org.openide.filesystems.FileUtil; +import org.openide.filesystems.URLMapper; +import org.openide.util.NbBundle; + +/** + * Representation of an expandable group category in ActionsPanel + * + * @author Martin + */ +abstract class BreakpointsExpandableGroup implements OutlineComboBox.Expandable { + + private boolean expanded = false; + private T[] items; + + @Override + public boolean isExpanded() { + return expanded; + } + + @Override + public void setExpanded(boolean expanded) { + this.expanded = expanded; + } + + @Override + public T[] getItems() { + if (items == null) { + items = createItems(); + } + return items; + } + + protected abstract T[] createItems(); + + static class FilesGroup extends BreakpointsExpandableGroup { + + @Override + public FileItem[] createItems() { + Set items = new TreeSet(); + Breakpoint[] bs = DebuggerManager.getDebuggerManager ().getBreakpoints (); + for (int i = 0; i < bs.length; i++) { + GroupProperties groupProperties = bs[i].getGroupProperties(); + if (groupProperties != null) { + FileObject[] files = groupProperties.getFiles(); + if (files != null) { + for (FileObject fo : files) { + items.add(new FileItem(fo)); + } + } + } + } + return items.toArray(new FileItem[]{}); + } + + @Override + public String toString() { + return NbBundle.getMessage(ActionsPanel.class, "LBL_FilesGroup"); + } + + } + + static class ProjectsGroup extends BreakpointsExpandableGroup { + + @Override + public ProjectItem[] createItems() { + Set items = new TreeSet(); + Breakpoint[] bs = DebuggerManager.getDebuggerManager ().getBreakpoints (); + for (int i = 0; i < bs.length; i++) { + GroupProperties groupProperties = bs[i].getGroupProperties(); + if (groupProperties != null) { + Project[] projects = groupProperties.getProjects(); + if (projects != null) { + for (Project p : projects) { + items.add(new ProjectItem(p)); + } + } + } + } + return items.toArray(new ProjectItem[]{}); + } + + @Override + public String toString() { + return NbBundle.getMessage(ActionsPanel.class, "LBL_ProjectsGroup"); + } + + } + + static class TypesGroup extends BreakpointsExpandableGroup { + + @Override + public TypeItem[] createItems() { + Set items = new TreeSet(); + Breakpoint[] bs = DebuggerManager.getDebuggerManager ().getBreakpoints (); + for (int i = 0; i < bs.length; i++) { + GroupProperties groupProperties = bs[i].getGroupProperties(); + if (groupProperties != null) { + String type = groupProperties.getType(); + if (type != null) { + items.add(new TypeItem(type)); + } + } + } + return items.toArray(new TypeItem[]{}); + } + + @Override + public String toString() { + return NbBundle.getMessage(ActionsPanel.class, "LBL_TypesGroup"); + } + + } + + static class FileItem implements Comparable, PopupMenuItem { + + private FileObject fo; + + public FileItem(FileObject fo) { + this.fo = fo; + } + + public FileObject getFileObject() { + return fo; + } + + @Override + public int hashCode() { + return fo.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof FileItem) && ((FileItem) obj).fo.equals(fo); + } + + @Override + public int compareTo(FileItem o) { + return o.toString().compareTo(toString()); + } + + @Override + public String toString() { + try { + return fo.getURL().toExternalForm(); + } catch (FileStateInvalidException ex) { + return "file://"+fo.getPath(); + } + } + + @Override + public String toPopupMenuString() { + //return FileUtil.getFileDisplayName(fo); + return fo.getNameExt(); + } + + public static Object valueOf(String newString) { + URL url; + try { + url = new URL(newString); + } catch (MalformedURLException ex) { + return newString; + } + FileObject fo = URLMapper.findFileObject(url); + if (fo != null) { + return new FileItem(fo); + } else { + return newString; + } + } + + } + + static class ProjectItem implements Comparable, PopupMenuItem { + + private Project p; + + public ProjectItem(Project p) { + this.p = p; + } + + public Project getProject() { + return p; + } + + @Override + public int hashCode() { + return p.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof ProjectItem) && ((ProjectItem) obj).p.equals(p); + } + + @Override + public int compareTo(ProjectItem o) { + return o.toString().compareTo(toString()); + } + + @Override + public String toString() { + return NbBundle.getMessage(ActionsPanel.class, "LBL_ProjectGroupItem", p.getProjectDirectory().getPath()); + } + + @Override + public String toPopupMenuString() { + return ProjectUtils.getInformation(p).getDisplayName(); + } + + public static Object valueOf(String newString) { + String format = NbBundle.getMessage(ActionsPanel.class, "LBL_ProjectGroupItem", ""); + String dir = getFormattedValue(format, newString); + if (dir != null) { + FileObject fo = FileUtil.toFileObject(new java.io.File(dir)); + if (fo != null) { + try { + Project project = ProjectManager.getDefault().findProject(fo); + if (project != null) { + return new ProjectItem(project); + } + } catch (IOException ex) { + } catch (IllegalArgumentException ex) { + } + } + } + return newString; + } + + } + + static class TypeItem implements Comparable, PopupMenuItem { + + private String type; + + public TypeItem(String type) { + this.type = type; + } + + public String getType() { + return type; + } + + @Override + public int hashCode() { + return type.hashCode(); + } + + @Override + public boolean equals(Object obj) { + return (obj instanceof TypeItem) && ((TypeItem) obj).type.equals(type); + } + + @Override + public int compareTo(TypeItem o) { + return o.toString().compareTo(toString()); + } + + @Override + public String toString() { + return NbBundle.getMessage(ActionsPanel.class, "LBL_TypeGroupItem", type); + } + + @Override + public String toPopupMenuString() { + return type; + } + + public static Object valueOf(String newString) { + String format = NbBundle.getMessage(ActionsPanel.class, "LBL_ProjectGroupItem", ""); + String type = getFormattedValue(format, newString); + if (type != null) { + return new TypeItem(type); + } + return newString; + } + } + + private static String getFormattedValue(String format, String newString) { + int i; + for (i = 0; i < newString.length() && i < format.length(); i++) { + if (Character.toUpperCase(newString.charAt(i)) != + Character.toUpperCase(format.charAt(i))) { + + break; + } + } + int i2 = format.length() - 1; + int i2ns = newString.length() - 1; + for (; i2 > i && i2ns > i; i2--, i2ns--) { + if (Character.toUpperCase(newString.charAt(i2ns)) != + Character.toUpperCase(format.charAt(i2))) { + + break; + } + } + if (i >= i2 && i <= i2ns) { + return newString.substring(i, i2ns + 1); + } else { + return null; + } + } + +} diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/Bundle.properties b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/Bundle.properties --- a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/Bundle.properties +++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/Bundle.properties @@ -60,6 +60,15 @@ LBL_CB_Actions_Panel_Suspend_All=All threads TTT_CB_Actions_Panel_Suspend=The suspend mode. + MSG_EnableGroup=Enable Group: + MSG_DisableGroup=Disable Group: + LBL_NoneBreakpointGroup= + LBL_FilesGroup=Breakpoints in Files + LBL_ProjectsGroup=Breakpoints in Projects + LBL_TypesGroup=Breakpoint Types + LBL_ProjectGroupItem=Project: {0} + LBL_TypeGroupItem=Breakpoint Type: {0} + L_Actions_Panel_Print_Text=Print &Text\: ACSD_TF_Actions_Panel_Print_Text= diff --git a/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/OutlineComboBox.java b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/OutlineComboBox.java new file mode 100644 --- /dev/null +++ b/debugger.jpda.ui/src/org/netbeans/modules/debugger/jpda/ui/breakpoints/OutlineComboBox.java @@ -0,0 +1,262 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.debugger.jpda.ui.breakpoints; + +import java.awt.Component; +import java.awt.Graphics; +import java.awt.Insets; +import java.util.HashSet; +import java.util.Set; +import javax.swing.DefaultComboBoxModel; +import javax.swing.Icon; +import javax.swing.JComboBox; +import javax.swing.JLabel; +import javax.swing.JList; +import javax.swing.ListCellRenderer; +import javax.swing.SwingUtilities; +import javax.swing.UIManager; +import javax.swing.border.Border; + +/** + * Combo box with a tree-like outline in the popup menu. + * Only one expansion level is supported, for simplicity. + * + * @author martin + */ +public class OutlineComboBox extends JComboBox { + + private JList popupList; + private boolean keepPopupVisible = false; + private Set expandedItems = new HashSet(); + + public OutlineComboBox() { + setRenderer(new OutlineComboBoxRenderer()); + } + + public void setItems(Object[] items) { + expandedItems.clear(); + setModel(new OutlineComboBoxModel(items)); + } + + private void setKeepPopupVisible(boolean keepPopupVisible) { + this.keepPopupVisible = keepPopupVisible; + } + + @Override + public void setPopupVisible(boolean v) { + if (v || !keepPopupVisible) { + super.setPopupVisible(v); + } + } + + public static interface Expandable { + + Object[] getItems(); + + boolean isExpanded(); + + void setExpanded(boolean expanded); + + } + + public static interface PopupMenuItem { + + String toPopupMenuString(); + } + + private class OutlineComboBoxModel extends DefaultComboBoxModel { + + public OutlineComboBoxModel(Object[] items) { + super(items); + } + + @Override + public void setSelectedItem(Object item) { + if (item instanceof Expandable) { + Expandable exp = (Expandable) item; + exp.setExpanded(!exp.isExpanded()); + if (popupList != null) { + OutlineComboBox.this.setKeepPopupVisible(true); + popupList.repaint(); + SwingUtilities.invokeLater(new Runnable() { + @Override + public void run() { + OutlineComboBox.this.setKeepPopupVisible(false); + } + }); + } + addRemoveSubItems(exp); + } else { + super.setSelectedItem(item); + } + } + + private void addRemoveSubItems(Expandable exp) { + int index = getIndexOf(exp); + if (exp.isExpanded()) { + for (Object item : exp.getItems()) { + insertElementAt(item, ++index); + expandedItems.add(item); + } + } else { + index++; + for (Object item : exp.getItems()) { + removeElementAt(index); + expandedItems.remove(item); + } + } + } + } + + private class OutlineComboBoxRenderer extends JLabel + implements ListCellRenderer { + + private ShiftBorder sborder; + + public OutlineComboBoxRenderer() { + setOpaque(true); + sborder = new ShiftBorder(getBorder()); + setBorder(sborder); + } + + @Override + public Component getListCellRendererComponent( + JList list, + Object value, + int index, + boolean isSelected, + boolean cellHasFocus) { + popupList = list; + if (value instanceof Expandable) { + Expandable exp = (Expandable) value; + if (exp.isExpanded()) { + setIcon(getExpandedIcon()); + } else { + setIcon(getCollapsedIcon()); + } + } else { + setIcon(null); + } + String text; + if (value instanceof PopupMenuItem) { + text = ((PopupMenuItem) value).toPopupMenuString(); + } else { + text = value.toString(); + } + setText(text); + if (expandedItems.contains(value)) { + sborder.setShift(getExpansionHandleWidth()); + } else { + sborder.setShift(0); + } + + if (isSelected) { + setBackground(list.getSelectionBackground()); + setForeground(list.getSelectionForeground()); + } else { + setBackground(list.getBackground()); + setForeground(list.getForeground()); + } + return this; + } + + private class ShiftBorder implements Border { + + private Border b; + private int shift; + private Insets NO_INSETS = new Insets(0, 0, 0, 0); + + public ShiftBorder(Border b) { + this.b = b; + } + + public void setShift(int shift) { + this.shift = shift; + } + + @Override + public void paintBorder(Component c, Graphics g, int x, int y, int width, int height) { + if (b != null) { + b.paintBorder(c, g, x, y, width, height); + } + } + + @Override + public Insets getBorderInsets(Component c) { + Insets in; + if (b == null) { + in = NO_INSETS; + } else { + in = b.getBorderInsets(c); + } + if (shift != 0) { + in = new Insets(in.top, shift + in.left, in.bottom, in.right); + } + return in; + } + + @Override + public boolean isBorderOpaque() { + if (b == null) return false; + return b.isBorderOpaque(); + } + + } + } + + private static Icon getExpandedIcon() { + return UIManager.getIcon ("Tree.expandedIcon"); //NOI18N + } + + private static Icon getCollapsedIcon() { + return UIManager.getIcon ("Tree.collapsedIcon"); //NOI18N + } + + private static int expansionHandleWidth; + private static int getExpansionHandleWidth() { + if (expansionHandleWidth == 0) { + expansionHandleWidth = getExpandedIcon ().getIconWidth (); + } + return expansionHandleWidth; + } + +} diff --git a/debugger.jpda/nbproject/project.xml b/debugger.jpda/nbproject/project.xml --- a/debugger.jpda/nbproject/project.xml +++ b/debugger.jpda/nbproject/project.xml @@ -55,7 +55,7 @@ 1 - 1.28 + 1.34 @@ -119,6 +119,15 @@ + org.netbeans.modules.projectapi + + + + 1 + 1.39 + + + org.netbeans.spi.debugger.ui diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointImpl.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointImpl.java --- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointImpl.java +++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointImpl.java @@ -66,6 +66,7 @@ import java.beans.PropertyChangeEvent; import java.util.HashMap; import java.util.Map; +import java.util.Set; import java.util.logging.Level; import java.util.logging.Logger; import javax.swing.SwingUtilities; @@ -471,6 +472,7 @@ getBreakpoint (), e ); + enableDisableDependentBreakpoints(); Integer brkpSuspend = (Integer) event.request().getProperty("brkpSuspend"); if (brkpSuspend == null) { brkpSuspend = getBreakpoint().getSuspend(); @@ -493,6 +495,17 @@ return resume; } + private void enableDisableDependentBreakpoints() { + Set breakpoints = breakpoint.getBreakpointsToEnable(); + for (Breakpoint b : breakpoints) { + b.enable(); + } + breakpoints = breakpoint.getBreakpointsToDisable(); + for (Breakpoint b : breakpoints) { + b.disable(); + } + } + private boolean checkWhetherResumeToFinishStep(ThreadReference thread) throws InternalExceptionWrapper, VMDisconnectedExceptionWrapper { List stepRequests = EventRequestManagerWrapper.stepRequests( VirtualMachineWrapper.eventRequestManager(MirrorWrapper.virtualMachine(thread))); diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsFromGroup.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsFromGroup.java new file mode 100644 --- /dev/null +++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsFromGroup.java @@ -0,0 +1,232 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2011 Oracle and/or its affiliates. All rights reserved. + * + * Oracle and Java are registered trademarks of Oracle and/or its affiliates. + * Other names may be trademarks of their respective owners. + * + * The contents of this file are subject to the terms of either the GNU + * General Public License Version 2 only ("GPL") or the Common + * Development and Distribution License("CDDL") (collectively, the + * "License"). You may not use this file except in compliance with the + * License. You can obtain a copy of the License at + * http://www.netbeans.org/cddl-gplv2.html + * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the + * specific language governing permissions and limitations under the + * License. When distributing the software, include this License Header + * Notice in each file and include the License file at + * nbbuild/licenses/CDDL-GPL-2-CP. Oracle designates this + * particular file as subject to the "Classpath" exception as provided + * by Oracle in the GPL Version 2 section of the License file that + * accompanied this code. If applicable, add the following below the + * License Header, with the fields enclosed by brackets [] replaced by + * your own identifying information: + * "Portions Copyrighted [year] [name of copyright owner]" + * + * If you wish your version of this file to be governed by only the CDDL + * or only the GPL Version 2, indicate your decision by adding + * "[Contributor] elects to include this software in this distribution + * under the [CDDL or GPL Version 2] license." If you do not indicate a + * single choice of license, a recipient has the option to distribute + * your version of this file under either the CDDL, the GPL Version 2 or + * to extend the choice of license to its licensees as provided above. + * However, if you add GPL Version 2 code and therefore, elected the GPL + * Version 2 license, then the option applies only if the new code is + * made subject to such option by the copyright holder. + * + * Contributor(s): + * + * Portions Copyrighted 2011 Sun Microsystems, Inc. + */ +package org.netbeans.modules.debugger.jpda.breakpoints; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Iterator; +import java.util.List; +import java.util.Set; + +import org.netbeans.api.debugger.Breakpoint; +import org.netbeans.api.debugger.Breakpoint.GroupProperties; +import org.netbeans.api.debugger.DebuggerManager; +import org.netbeans.api.project.Project; +import org.openide.filesystems.FileObject; + +/** + * Set of breakpoints from a group. + * + * @author Martin + */ +public final class BreakpointsFromGroup implements Set { + + private final String groupName; + private final TestGroupProperties testProperties; + + public BreakpointsFromGroup(String groupName) { + this.groupName = groupName; + this.testProperties = null; + } + + public BreakpointsFromGroup(TestGroupProperties testProperties) { + this.groupName = null; + this.testProperties = testProperties; + } + + public String getGroupName() { + return groupName; + } + + public TestGroupProperties getTestGroupProperties() { + return testProperties; + } + + private List getBreakpointsFromGroup() { + List breakpoints = new ArrayList(); + Breakpoint[] bps = DebuggerManager.getDebuggerManager().getBreakpoints(); + if (groupName != null) { + for (Breakpoint b : bps) { + if (groupName.equals(b.getGroupName())) { + breakpoints.add(b); + } + } + } else if (testProperties != null) { + for (Breakpoint b : bps) { + GroupProperties groupProperties = b.getGroupProperties(); + if (groupProperties != null && + !groupProperties.isHidden() && + testProperties.accept(groupProperties)) { + + breakpoints.add(b); + } + } + } + return breakpoints; + } + + @Override + public int size() { + return getBreakpointsFromGroup().size(); + } + + @Override + public boolean isEmpty() { + return getBreakpointsFromGroup().isEmpty(); + } + + @Override + public boolean contains(Object o) { + return getBreakpointsFromGroup().contains(o); + } + + @Override + public Iterator iterator() { + return getBreakpointsFromGroup().iterator(); + } + + @Override + public boolean containsAll(Collection c) { + return getBreakpointsFromGroup().containsAll(c); + } + + @Override + public Object[] toArray() { + return getBreakpointsFromGroup().toArray(); + } + + @Override + public T[] toArray(T[] a) { + return getBreakpointsFromGroup().toArray(a); + } + + @Override + public boolean add(Breakpoint e) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public boolean remove(Object o) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public boolean addAll(Collection c) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public boolean retainAll(Collection c) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public boolean removeAll(Collection c) { + throw new UnsupportedOperationException("Not supported."); + } + + @Override + public void clear() { + throw new UnsupportedOperationException("Not supported."); + } + + public static final class TestGroupProperties { + + private FileObject fo; + private Project p; + private String type; + + public TestGroupProperties(FileObject fo) { + this.fo = fo; + } + + public TestGroupProperties(Project p) { + this.p = p; + } + + public TestGroupProperties(String type) { + this.type = type; + } + + public FileObject getFileObject() { + return fo; + } + + public Project getProject() { + return p; + } + + public String getType() { + return type; + } + + boolean accept(GroupProperties gp) { + if (fo != null) { + FileObject[] files = gp.getFiles(); + if (files != null) { + for (FileObject f : files) { + if (fo.equals(f)) { + return true; + } + } + } + } + if (p != null) { + Project[] projects = gp.getProjects(); + if (projects != null) { + for (Project pp : projects) { + if (p.equals(pp)) { + return true; + } + } + } + } + if (type != null) { + if (type.equals(gp.getType())) { + return true; + } + } + return false; + } + } + +} diff --git a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsReader.java b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsReader.java --- a/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsReader.java +++ b/debugger.jpda/src/org/netbeans/modules/debugger/jpda/breakpoints/BreakpointsReader.java @@ -46,7 +46,12 @@ import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeListener; +import java.io.IOException; +import java.net.MalformedURLException; +import java.net.URL; +import java.util.Collections; import java.util.Map; +import java.util.Set; import java.util.WeakHashMap; import org.netbeans.api.debugger.Breakpoint; @@ -58,7 +63,14 @@ import org.netbeans.api.debugger.jpda.LineBreakpoint; import org.netbeans.api.debugger.jpda.MethodBreakpoint; import org.netbeans.api.debugger.jpda.ThreadBreakpoint; +import org.netbeans.api.project.Project; +import org.netbeans.api.project.ProjectManager; +import org.netbeans.modules.debugger.jpda.breakpoints.BreakpointsFromGroup.TestGroupProperties; import org.netbeans.spi.debugger.DebuggerServiceRegistration; +import org.openide.filesystems.FileObject; +import org.openide.filesystems.FileStateInvalidException; +import org.openide.filesystems.URLMapper; +import org.openide.util.Exceptions; /** @@ -68,6 +80,13 @@ @DebuggerServiceRegistration(types={Properties.Reader.class}) public class BreakpointsReader implements Properties.Reader, PropertyChangeListener { + private static final String BREAKPOINTS_TO_ENABLE = "breakpointsToEnable"; + private static final String BREAKPOINTS_TO_DISABLE = "breakpointsToDisable"; + private static final String BP_CUSTOM_GROUP = "CustomGroup"; + private static final String BP_FILE_GROUP = "FileGroup"; + private static final String BP_PROJECT_GROUP = "ProjectGroup"; + private static final String BP_TYPE_GROUP = "TypeGroup"; + private Map cachedClassNames = new WeakHashMap(); private Map cachedSourceRoots = new WeakHashMap(); @@ -274,9 +293,86 @@ b.enable (); else b.disable (); + b.setBreakpointsToEnable(getBreakpointsFromGroup(properties, BREAKPOINTS_TO_ENABLE)); + b.setBreakpointsToDisable(getBreakpointsFromGroup(properties, BREAKPOINTS_TO_DISABLE)); return b; } + private static Set getBreakpointsFromGroup(Properties properties, String base) { + String bpGroup = properties.getString(base + BP_CUSTOM_GROUP, null); + if (bpGroup != null) { + return new BreakpointsFromGroup(bpGroup); + } + bpGroup = properties.getString(base + BP_FILE_GROUP, null); + if (bpGroup != null) { + try { + URL url = new URL(bpGroup); + FileObject fo = URLMapper.findFileObject(url); + if (fo != null) { + return new BreakpointsFromGroup(new TestGroupProperties(fo)); + } + } catch (MalformedURLException ex) { + } + } + bpGroup = properties.getString(base + BP_PROJECT_GROUP, null); + if (bpGroup != null) { + try { + URL url = new URL(bpGroup); + FileObject fo = URLMapper.findFileObject(url); + if (fo != null) { + Project project = ProjectManager.getDefault().findProject(fo); + if (project != null) { + return new BreakpointsFromGroup(new TestGroupProperties(project)); + } + } + } catch (MalformedURLException ex) { + } catch (IOException ex) { + } catch (IllegalArgumentException ex) { + } + } + bpGroup = properties.getString(base + BP_TYPE_GROUP, null); + if (bpGroup != null) { + return new BreakpointsFromGroup(new TestGroupProperties(bpGroup)); + } + return Collections.EMPTY_SET; + } + + private static void setBreakpointsFromGroup(Properties properties, String base, Set breakpointsFromGroup) { + String customGroup = null; + String fileURL = null; + String projectURL = null; + String type = null; + if (breakpointsFromGroup instanceof BreakpointsFromGroup) { + BreakpointsFromGroup bfg = (BreakpointsFromGroup) breakpointsFromGroup; + customGroup = bfg.getGroupName(); + TestGroupProperties tgp = bfg.getTestGroupProperties(); + if (tgp != null) { + FileObject fo = tgp.getFileObject(); + if (fo != null) { + try { + URL url = fo.getURL(); + fileURL = url.toExternalForm(); + } catch (FileStateInvalidException ex) { + } + } + Project project = tgp.getProject(); + if (project != null) { + fo = project.getProjectDirectory(); + try { + URL url = fo.getURL(); + projectURL = url.toExternalForm(); + } catch (FileStateInvalidException ex) { + } + } + type = tgp.getType(); + } + } + properties.setString(base + BP_CUSTOM_GROUP, customGroup); + properties.setString(base + BP_FILE_GROUP, fileURL); + properties.setString(base + BP_PROJECT_GROUP, projectURL); + properties.setString(base + BP_TYPE_GROUP, type); + } + public void write (Object object, Properties properties) { JPDABreakpoint b = (JPDABreakpoint) object; properties.setString ( @@ -292,6 +388,10 @@ properties.setInt(JPDABreakpoint.PROP_HIT_COUNT_FILTER, b.getHitCountFilter()); Breakpoint.HIT_COUNT_FILTERING_STYLE style = b.getHitCountFilteringStyle(); properties.setInt(JPDABreakpoint.PROP_HIT_COUNT_FILTER+"_style", style != null ? style.ordinal() : 0); // NOI18N + Set breakpointsToEnable = b.getBreakpointsToEnable(); + setBreakpointsFromGroup(properties, BREAKPOINTS_TO_ENABLE, breakpointsToEnable); + Set breakpointsToDisable = b.getBreakpointsToDisable(); + setBreakpointsFromGroup(properties, BREAKPOINTS_TO_DISABLE, breakpointsToDisable); if (object instanceof LineBreakpoint) { LineBreakpoint lb = (LineBreakpoint) object;