This Bugzilla instance is a read-only archive of historic NetBeans bug reports. To report a bug in NetBeans please follow the project's instructions for reporting issues.

View | Details | Raw Unified | Return to bug 258651
Collapse All | Expand All

(-)a/api.debugger/apichanges.xml (+16 lines)
Lines 75-80 Link Here
75
<!-- ACTUAL CHANGES BEGIN HERE: -->
75
<!-- ACTUAL CHANGES BEGIN HERE: -->
76
76
77
<changes>
77
<changes>
78
    <change id="Watch_Pin">
79
        <api name="DebuggerCoreAPI"/>
80
        <summary>API for pinned Watches</summary>
81
        <version major="1" minor="54"/>
82
        <date day="12" month="4" year="2016"/>
83
        <author login="mentlicher"/>
84
        <compatibility binary="compatible" source="compatible" addition="yes" deletion="no"/>
85
        <description>
86
            A <code>Watch.Pin</code> base interface introduced as a basis
87
            for specific platform-dependent and location-dependent implementations.
88
            <code>DebuggerManager.createPinnedwatch()</code> introduced.
89
        </description>
90
        <class package="org.netbeans.api.debugger" name="DebuggerManager"/>
91
        <class package="org.netbeans.api.debugger" name="Watch"/>
92
        <issue number="258651"/>
93
    </change>
78
    <change id="Watch_disableable">
94
    <change id="Watch_disableable">
79
        <api name="DebuggerCoreAPI"/>
95
        <api name="DebuggerCoreAPI"/>
80
        <summary>API for changing enabled state of a Watch</summary>
96
        <summary>API for changing enabled state of a Watch</summary>
(-)a/api.debugger/manifest.mf (-1 / +1 lines)
Lines 1-5 Link Here
1
Manifest-Version: 1.0
1
Manifest-Version: 1.0
2
OpenIDE-Module: org.netbeans.api.debugger/1
2
OpenIDE-Module: org.netbeans.api.debugger/1
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/api/debugger/Bundle.properties
4
OpenIDE-Module-Specification-Version: 1.53
4
OpenIDE-Module-Specification-Version: 1.54
5
OpenIDE-Module-Layer: org/netbeans/api/debugger/layer.xml
5
OpenIDE-Module-Layer: org/netbeans/api/debugger/layer.xml
(-)a/api.debugger/src/org/netbeans/api/debugger/DebuggerManager.java (+21 lines)
Lines 665-670 Link Here
665
        }
665
        }
666
        return w;
666
        return w;
667
    }
667
    }
668
    
669
    /**
670
     * Create a watch pinned at the specified pin location.
671
     * @param expr expression to watch for (the format is the responsibility
672
     *    of the debugger plug-in implementation, but it is typically
673
     *    a variable name).
674
     * @param pin A pin where the watch should be pinned at.
675
     * @return the new watch
676
     * @since 1.54
677
     */
678
    public Watch createPinnedWatch(String expr, Watch.Pin pin) {
679
        Watch w = new Watch (expr, pin);
680
        if (Boolean.TRUE.equals(watchesInitializing.get())) {
681
            watches.addElement (w);
682
        } else {
683
            initWatches ();
684
            watches.addElement (w);
685
            fireWatchCreated (w);
686
        }
687
        return w;
688
    }
668
689
669
    /**
690
    /**
670
    * Gets all shared watches in the system.
691
    * Gets all shared watches in the system.
(-)a/api.debugger/src/org/netbeans/api/debugger/Watch.java (-2 / +27 lines)
Lines 47-53 Link Here
47
import java.beans.PropertyChangeListener;
47
import java.beans.PropertyChangeListener;
48
import java.beans.PropertyChangeSupport;
48
import java.beans.PropertyChangeSupport;
49
49
50
51
/**
50
/**
52
 * Abstract definition of watch. Each watch is created for
51
 * Abstract definition of watch. Each watch is created for
53
 * one String which contains the name of variable or some expression.
52
 * one String which contains the name of variable or some expression.
Lines 68-76 Link Here
68
    private boolean         enabled = true;
67
    private boolean         enabled = true;
69
    private PropertyChangeSupport pcs;
68
    private PropertyChangeSupport pcs;
70
    
69
    
70
    private final Pin pin;
71
    
71
    
72
    Watch (String expr) {
72
    Watch (String expr) {
73
        this(expr, null);
74
    }
75
    
76
    Watch (String expr, Pin pin) {
73
        this.expression = expr;
77
        this.expression = expr;
78
        this.pin = pin;
74
        pcs = new PropertyChangeSupport (this);
79
        pcs = new PropertyChangeSupport (this);
75
    }
80
    }
76
    
81
    
Lines 121-127 Link Here
121
        }
126
        }
122
        pcs.firePropertyChange (PROP_EXPRESSION, old, expression);
127
        pcs.firePropertyChange (PROP_EXPRESSION, old, expression);
123
    }
128
    }
124
    
129
130
    /**
131
     * Get a pin location, where the watch is pinned at, if any.
132
     * @return The watch pin, or <code>null</code>.
133
     * @since 1.54
134
     */
135
    public Pin getPin() {
136
        return pin;
137
    }
138
125
    /**
139
    /**
126
     * Remove the watch from the list of all watches in the system.
140
     * Remove the watch from the list of all watches in the system.
127
     */
141
     */
Lines 147-151 Link Here
147
    public void removePropertyChangeListener (PropertyChangeListener l) {
161
    public void removePropertyChangeListener (PropertyChangeListener l) {
148
        pcs.removePropertyChangeListener (l);
162
        pcs.removePropertyChangeListener (l);
149
    }
163
    }
164
    
165
    /**
166
     * A base interface for a watch pin location. Implemented by specific
167
     * platform-dependent and location-dependent implementation.
168
     * See <code>org.netbeans.spi.debugger.ui.EditorPin</code> for the NetBeans
169
     * editor pin implementation.
170
     * @since 1.54
171
     */
172
    public static interface Pin {
173
        
174
    }
150
}
175
}
151
176
(-)a/spi.debugger.ui/manifest.mf (-1 / +1 lines)
Lines 2-7 Link Here
2
OpenIDE-Module: org.netbeans.spi.debugger.ui/1
2
OpenIDE-Module: org.netbeans.spi.debugger.ui/1
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/debugger/ui/Bundle.properties
3
OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/debugger/ui/Bundle.properties
4
OpenIDE-Module-Layer: org/netbeans/modules/debugger/resources/mf-layer.xml
4
OpenIDE-Module-Layer: org/netbeans/modules/debugger/resources/mf-layer.xml
5
OpenIDE-Module-Specification-Version: 2.52
5
OpenIDE-Module-Specification-Version: 2.53
6
OpenIDE-Module-Provides: org.netbeans.spi.debugger.ui
6
OpenIDE-Module-Provides: org.netbeans.spi.debugger.ui
7
OpenIDE-Module-Install: org/netbeans/modules/debugger/ui/DebuggerModule.class
7
OpenIDE-Module-Install: org/netbeans/modules/debugger/ui/DebuggerModule.class
(-)a/spi.debugger.ui/nbproject/project.properties (-1 / +1 lines)
Lines 42-48 Link Here
42
42
43
is.autoload=true
43
is.autoload=true
44
javac.compilerargs=-Xlint -Xlint:-serial
44
javac.compilerargs=-Xlint -Xlint:-serial
45
javac.source=1.7
45
javac.source=1.8
46
javadoc.arch=${basedir}/arch.xml
46
javadoc.arch=${basedir}/arch.xml
47
47
48
test.config.stableBTD.includes=**/*Test.class
48
test.config.stableBTD.includes=**/*Test.class
(-)a/spi.debugger.ui/nbproject/project.xml (+17 lines)
Lines 50-55 Link Here
50
            <code-name-base>org.netbeans.spi.debugger.ui</code-name-base>
50
            <code-name-base>org.netbeans.spi.debugger.ui</code-name-base>
51
            <module-dependencies>
51
            <module-dependencies>
52
                <dependency>
52
                <dependency>
53
                    <code-name-base>org.netbeans.api.annotations.common</code-name-base>
54
                    <build-prerequisite/>
55
                    <compile-dependency/>
56
                    <run-dependency>
57
                        <release-version>1</release-version>
58
                        <specification-version>1.27</specification-version>
59
                    </run-dependency>
60
                </dependency>
61
                <dependency>
53
                    <code-name-base>org.netbeans.api.debugger</code-name-base>
62
                    <code-name-base>org.netbeans.api.debugger</code-name-base>
54
                    <build-prerequisite/>
63
                    <build-prerequisite/>
55
                    <compile-dependency/>
64
                    <compile-dependency/>
Lines 68-73 Link Here
68
                    </run-dependency>
77
                    </run-dependency>
69
                </dependency>
78
                </dependency>
70
                <dependency>
79
                <dependency>
80
                    <code-name-base>org.netbeans.modules.editor.document</code-name-base>
81
                    <build-prerequisite/>
82
                    <compile-dependency/>
83
                    <run-dependency>
84
                        <specification-version>1.6</specification-version>
85
                    </run-dependency>
86
                </dependency>
87
                <dependency>
71
                    <code-name-base>org.netbeans.modules.editor.fold</code-name-base>
88
                    <code-name-base>org.netbeans.modules.editor.fold</code-name-base>
72
                    <build-prerequisite/>
89
                    <build-prerequisite/>
73
                    <compile-dependency/>
90
                    <compile-dependency/>
(-)a/spi.debugger.ui/src/org/netbeans/modules/debugger/resources/Bundle.properties (+1 lines)
Lines 118-120 Link Here
118
HINT_CURRENT_EXP_LINE_DCBP=Current Program Counter In Expression + Disabled Conditional Breakpoint
118
HINT_CURRENT_EXP_LINE_DCBP=Current Program Counter In Expression + Disabled Conditional Breakpoint
119
HINT_CURRENT_EXP=Current Expression
119
HINT_CURRENT_EXP=Current Expression
120
120
121
HINT_WATCH_PIN=Watch
(-)a/spi.debugger.ui/src/org/netbeans/modules/debugger/resources/WatchPin.xml (+55 lines)
Line 0 Link Here
1
<?xml version="1.0" encoding="UTF-8"?>
2
<!--
3
DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
4
5
Copyright 2016 Oracle and/or its affiliates. All rights reserved.
6
7
Oracle and Java are registered trademarks of Oracle and/or its affiliates.
8
Other names may be trademarks of their respective owners.
9
10
The contents of this file are subject to the terms of either the GNU
11
General Public License Version 2 only ("GPL") or the Common
12
Development and Distribution License("CDDL") (collectively, the
13
"License"). You may not use this file except in compliance with the
14
License. You can obtain a copy of the License at
15
http://www.netbeans.org/cddl-gplv2.html
16
or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
17
specific language governing permissions and limitations under the
18
License.  When distributing the software, include this License Header
19
Notice in each file and include the License file at
20
nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
21
particular file as subject to the "Classpath" exception as provided
22
by Oracle in the GPL Version 2 section of the License file that
23
accompanied this code. If applicable, add the following below the
24
License Header, with the fields enclosed by brackets [] replaced by
25
your own identifying information:
26
"Portions Copyrighted [year] [name of copyright owner]"
27
28
If you wish your version of this file to be governed by only the CDDL
29
or only the GPL Version 2, indicate your decision by adding
30
"[Contributor] elects to include this software in this distribution
31
under the [CDDL or GPL Version 2] license." If you do not indicate a
32
single choice of license, a recipient has the option to distribute
33
your version of this file under either the CDDL, the GPL Version 2 or
34
to extend the choice of license to its licensees as provided above.
35
However, if you add GPL Version 2 code and therefore, elected the GPL
36
Version 2 license, then the option applies only if the new code is
37
made subject to such option by the copyright holder.
38
39
Contributor(s):
40
41
Portions Copyrighted 2016 Sun Microsystems, Inc.
42
-->
43
44
<!DOCTYPE type PUBLIC "-//NetBeans//DTD annotation type 1.1//EN" "http://www.netbeans.org/dtds/annotation-type-1_1.dtd">
45
<type
46
    name='PinnedWatch'
47
    description_key='HINT_WATCH_PIN'
48
    localizing_bundle='org.netbeans.modules.debugger.resources.Bundle'
49
    visible='true'
50
    glyph='nbresloc:/org/netbeans/editor/resources/pin.png'
51
    type='line'
52
    severity='ok'
53
    priority='100'
54
    custom_sidebar_color='0xFF8FD5'
55
/>
(-)a/spi.debugger.ui/src/org/netbeans/modules/debugger/resources/mf-layer.xml (+1 lines)
Lines 542-547 Link Here
542
            <file name="mixed_BP_broken.xml" url="mixed_BP_broken.xml"/>
542
            <file name="mixed_BP_broken.xml" url="mixed_BP_broken.xml"/>
543
            <file name="PC_mixedBP.xml" url="PC_mixedBP.xml"/>
543
            <file name="PC_mixedBP.xml" url="PC_mixedBP.xml"/>
544
            <file name="PC_mixedBP_broken.xml" url="PC_mixedBP_broken.xml"/>
544
            <file name="PC_mixedBP_broken.xml" url="PC_mixedBP_broken.xml"/>
545
            <file name="WatchPin.xml" url="WatchPin.xml"/>
545
546
546
	<!-- following are invisible annotation types which are used for combining -->
547
	<!-- following are invisible annotation types which are used for combining -->
547
            <file name="_multi_BP.xml" url="_multi_BP.xml"/>
548
            <file name="_multi_BP.xml" url="_multi_BP.xml"/>
(-)a/spi.debugger.ui/src/org/netbeans/spi/debugger/ui/EditorPin.java (+177 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2016 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.spi.debugger.ui;
43
44
import java.awt.Point;
45
import java.beans.PropertyChangeListener;
46
import java.beans.PropertyChangeSupport;
47
import java.util.Objects;
48
import org.netbeans.api.debugger.Watch;
49
import org.openide.filesystems.FileObject;
50
51
/**
52
 * Implementation of watch pin in editor.
53
 * 
54
 * @author Ralph Benjamin Ruijs
55
 * @since 2.53
56
 */
57
public final class EditorPin implements Watch.Pin {
58
59
    /**
60
     * Line property, fired when a line change.
61
     */
62
    public static final String PROP_LINE = "line";
63
    /**
64
     * Location property, fired when a location change.
65
     */
66
    public static final String PROP_LOCATION = "location";
67
    /**
68
     * Comment property, fired when a comment change.
69
     */
70
    public static final String PROP_COMMENT = "comment";
71
72
    private final PropertyChangeSupport pchs = new PropertyChangeSupport(this);
73
74
    private final FileObject file;
75
    private volatile int line;
76
    private volatile Point location;
77
    private volatile String comment;
78
    private String vpId;
79
80
    /**
81
     * Create a new pin location in editor.
82
     * @param file The editor's file
83
     * @param line The line location of the pin
84
     * @param location Coordinates of the pin location in editor
85
     */
86
    public EditorPin(FileObject file, int line, Point location) {
87
        this.file = file;
88
        this.line = line;
89
        this.location = location;
90
    }
91
92
    /**
93
     * Get the line location of the pin.
94
     * @return The line.
95
     */
96
    public int getLine() {
97
        return line;
98
    }
99
100
    /**
101
     * Get the file object associated with the editor containing the pin.
102
     * @return The file object.
103
     */
104
    public FileObject getFile() {
105
        return file;
106
    }
107
108
    /**
109
     * Location of the pin in editor.
110
     * @return The location point.
111
     */
112
    public Point getLocation() {
113
        return location;
114
    }
115
116
    /**
117
     * Move the pin to a different location in the editor pane.
118
     * @param line A new line
119
     * @param location Coordinates of the new location
120
     */
121
    public void move(int line, Point location) {
122
        int oldLine = this.line;
123
        this.line = line;
124
        if (oldLine != line) {
125
            pchs.firePropertyChange(PROP_LINE, oldLine, line);
126
        }
127
        Point oldLocation = this.location;
128
        this.location = location;
129
        if (!oldLocation.equals(location)) {
130
            pchs.firePropertyChange(PROP_LOCATION, oldLocation, location);
131
        }
132
    }
133
134
    /**
135
     * Set a textual comment to this pin.
136
     * @param comment The user comment.
137
     */
138
    public void setComment(String comment) {
139
        String oldComment = this.comment;
140
        this.comment = comment;
141
        if (!Objects.equals(oldComment, comment)) {
142
            pchs.firePropertyChange(PROP_COMMENT, oldComment, comment);
143
        }
144
    }
145
146
    /**
147
     * Get the comment of this pin.
148
     * @return The comment or <code>null</code> when no comment is set.
149
     */
150
    public String getComment() {
151
        return comment;
152
    }
153
    
154
    void setVpId(String vpId) {
155
        this.vpId = vpId;
156
    }
157
158
    String getVpId() {
159
        return vpId;
160
    }
161
162
    /**
163
     * Add a listener for property change events to this editor pin.
164
     * @param listener The listener
165
     */
166
    public void addPropertyChangeListener(PropertyChangeListener listener) {
167
        pchs.addPropertyChangeListener(listener);
168
    }
169
170
    /**
171
     * Remove a listener for property change events from this editor pin.
172
     * @param listener The listener
173
     */
174
    public void removePropertyChangeListener(PropertyChangeListener listener) {
175
        pchs.removePropertyChangeListener(listener);
176
    }
177
}
(-)a/spi.debugger.ui/src/org/netbeans/spi/debugger/ui/PinWatchUISupport.java (+381 lines)
Line 0 Link Here
1
/*
2
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
3
 *
4
 * Copyright 2016 Oracle and/or its affiliates. All rights reserved.
5
 *
6
 * Oracle and Java are registered trademarks of Oracle and/or its affiliates.
7
 * Other names may be trademarks of their respective owners.
8
 *
9
 * The contents of this file are subject to the terms of either the GNU
10
 * General Public License Version 2 only ("GPL") or the Common
11
 * Development and Distribution License("CDDL") (collectively, the
12
 * "License"). You may not use this file except in compliance with the
13
 * License. You can obtain a copy of the License at
14
 * http://www.netbeans.org/cddl-gplv2.html
15
 * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
16
 * specific language governing permissions and limitations under the
17
 * License.  When distributing the software, include this License Header
18
 * Notice in each file and include the License file at
19
 * nbbuild/licenses/CDDL-GPL-2-CP.  Oracle designates this
20
 * particular file as subject to the "Classpath" exception as provided
21
 * by Oracle in the GPL Version 2 section of the License file that
22
 * accompanied this code. If applicable, add the following below the
23
 * License Header, with the fields enclosed by brackets [] replaced by
24
 * your own identifying information:
25
 * "Portions Copyrighted [year] [name of copyright owner]"
26
 *
27
 * If you wish your version of this file to be governed by only the CDDL
28
 * or only the GPL Version 2, indicate your decision by adding
29
 * "[Contributor] elects to include this software in this distribution
30
 * under the [CDDL or GPL Version 2] license." If you do not indicate a
31
 * single choice of license, a recipient has the option to distribute
32
 * your version of this file under either the CDDL, the GPL Version 2 or
33
 * to extend the choice of license to its licensees as provided above.
34
 * However, if you add GPL Version 2 code and therefore, elected the GPL
35
 * Version 2 license, then the option applies only if the new code is
36
 * made subject to such option by the copyright holder.
37
 *
38
 * Contributor(s):
39
 *
40
 * Portions Copyrighted 2016 Sun Microsystems, Inc.
41
 */
42
package org.netbeans.spi.debugger.ui;
43
44
import java.beans.Customizer;
45
import java.beans.PropertyChangeEvent;
46
import java.beans.PropertyChangeListener;
47
import java.util.HashMap;
48
import java.util.HashSet;
49
import java.util.List;
50
import java.util.Map;
51
import java.util.Set;
52
import org.netbeans.api.debugger.DebuggerEngine;
53
import org.netbeans.api.debugger.DebuggerManager;
54
import org.netbeans.api.debugger.DebuggerManagerAdapter;
55
import org.netbeans.api.debugger.Watch;
56
import org.netbeans.api.debugger.Watch.Pin;
57
import org.netbeans.modules.debugger.ui.annotations.WatchAnnotationProvider;
58
import org.netbeans.spi.debugger.DebuggerServiceRegistration;
59
import org.openide.loaders.DataObjectNotFoundException;
60
import org.openide.util.Exceptions;
61
import org.openide.util.NbBundle;
62
63
/**
64
 * Access to the default UI implementation of pin watches in editor.
65
 * Watches that are to be pinned by this support class, need to use the
66
 * {@link EditorPin} as the {@link Watch#getPin()} and an implementation
67
 * of {@link ValueProvider} needs to be register via {@link DebuggerServiceRegistration},
68
 * which acts as a supplier of the watch value.
69
 * <p>
70
 * Use {@link #pin(org.netbeans.api.debugger.Watch, java.lang.String)} to pin
71
 * the watch into editor where the corresponding {@link EditorPin} points at
72
 * and provide <code>valueProviderId</code> of the corresponding registered
73
 * {@link ValueProvider} which handles the value updates.
74
 * 
75
 * @author Martin Entlicher
76
 * @since 2.53
77
 */
78
public final class PinWatchUISupport {
79
    
80
    private static final PinWatchUISupport INSTANCE = new PinWatchUISupport();
81
    private final Object valueProvidersLock = new Object();
82
    private Map<String, DelegatingValueProvider> valueProviders;
83
    
84
    private PinWatchUISupport() {
85
        WatchAnnotationProvider.PIN_SUPPORT_ACCESS = new WatchAnnotationProvider.PinSupportedAccessor() {
86
            @Override
87
            public ValueProvider getValueProvider(EditorPin pin) {
88
                String id = pin.getVpId();
89
                if (id == null) {
90
                    return null;
91
                }
92
                synchronized (valueProvidersLock) {
93
                    return getValueProviders().get(id);
94
                }
95
            }
96
        };
97
        DebuggerManager.getDebuggerManager().addDebuggerListener(
98
                DebuggerManager.PROP_CURRENT_ENGINE,
99
                new DebuggerManagerAdapter() {
100
                    @Override
101
                    public void propertyChange(PropertyChangeEvent evt) {
102
                        refreshValueProviders();
103
                    }
104
                }
105
        );
106
    }
107
    
108
    /**
109
     * Get the default instance of this class.
110
     * @return An instance of {@link PinWatchUISupport} class.
111
     */
112
    public static PinWatchUISupport getDefault() {
113
        return INSTANCE;
114
    }
115
    
116
    /**
117
     * Pin the watch into an editor.
118
     * The pinned watch need to return {@link EditorPin} from {@link Watch#getPin()}
119
     * and a {@link ValueProvider} needs to be registered for the provided
120
     * <code>valueProviderId</code>.
121
     * @param watch A watch to pin at the location determined by the {@link EditorPin}.
122
     * @param valueProviderId An id of a registered {@link ValueProvider}.
123
     * @throws IllegalArgumentException is thrown when {@link Watch#getPin()}
124
     *                                  does not return an {@link EditorPin}, or
125
     *                                  when we're not able to find the editor
126
     *                                  where {@link EditorPin} points at.
127
     */
128
    public void pin(Watch watch, String valueProviderId) throws IllegalArgumentException {
129
        Pin wpin = watch.getPin();
130
        if (!(wpin instanceof EditorPin)) {
131
            throw new IllegalArgumentException("Unsupported pin: "+wpin);
132
        }
133
        synchronized (valueProvidersLock) {
134
            if (!getValueProviders().containsKey(valueProviderId)) {
135
                valueProviders.put(valueProviderId, new DelegatingValueProvider(valueProviderId));
136
            }
137
        }
138
        EditorPin pin = (EditorPin) wpin;
139
        pin.setVpId(valueProviderId);
140
        try {
141
            WatchAnnotationProvider.PIN_SUPPORT_ACCESS.pin(watch);
142
        } catch (DataObjectNotFoundException ex) {
143
            throw new IllegalArgumentException("Unable to find the pin's editor.", ex);
144
        }
145
    }
146
    
147
    private Map<String, DelegatingValueProvider> getValueProviders() {
148
        synchronized (valueProvidersLock) {
149
            if (valueProviders == null) {
150
                valueProviders = new HashMap<>();
151
                refreshValueProviders();
152
            }
153
            return valueProviders;
154
        }
155
    }
156
    
157
    private void refreshValueProviders() {
158
        DebuggerManager dm = DebuggerManager.getDebuggerManager ();
159
        DebuggerEngine e = dm.getCurrentEngine ();
160
        List<? extends ValueProvider> providers;
161
        if (e == null) {
162
            providers = dm.lookup (null, ValueProvider.class);
163
        } else {
164
            providers = DebuggerManager.join(e, dm).lookup (null, ValueProvider.class);
165
        }
166
        if (!providers.isEmpty()) {
167
            synchronized (valueProvidersLock) {
168
                if (valueProviders == null) {
169
                    valueProviders = new HashMap<>();
170
                }
171
                Set<String> existingProviderIds = new HashSet<>();
172
                for (ValueProvider provider : providers) {
173
                    String id = provider.getId();
174
                    existingProviderIds.add(id);
175
                    DelegatingValueProvider dvp = valueProviders.get(id);
176
                    if (dvp == null) {
177
                        dvp = new DelegatingValueProvider(id);
178
                        valueProviders.put(id, dvp);
179
                    }
180
                    dvp.setDelegate(provider);
181
                }
182
                Set<String> staleProviderIds = new HashSet<>(valueProviders.keySet());
183
                staleProviderIds.removeAll(existingProviderIds);
184
                for (String staleId : staleProviderIds) {
185
                    valueProviders.get(staleId).setDelegate(null);
186
                }
187
            }
188
        }
189
    }
190
    
191
    private static final class DelegatingValueProvider implements ValueProvider {
192
        
193
        private final String id;
194
        private volatile ValueProvider delegate;
195
        private final Map<Watch, ValueChangeListener> listeners = new HashMap<>();
196
        
197
        DelegatingValueProvider(String id) {
198
            this.id = id;
199
        }
200
201
        @Override
202
        public String getId() {
203
            return id;
204
        }
205
206
        @Override
207
        public String getValue(Watch watch) {
208
            ValueProvider vp = delegate;
209
            if (vp != null) {
210
                return vp.getValue(watch);
211
            } else {
212
                return null;
213
            }
214
        }
215
216
        @Override
217
        public String getEvaluatingText() {
218
            ValueProvider vp = delegate;
219
            if (vp != null) {
220
                return vp.getEvaluatingText();
221
            } else {
222
                return ValueProvider.super.getEvaluatingText();
223
            }
224
        }
225
226
        @Override
227
        public String getEditableValue(Watch watch) {
228
            ValueProvider vp = delegate;
229
            if (vp != null) {
230
                return vp.getEditableValue(watch);
231
            } else {
232
                return ValueProvider.super.getEditableValue(watch);
233
            }
234
        }
235
236
        @Override
237
        public boolean setValue(Watch watch, String value) {
238
            ValueProvider vp = delegate;
239
            if (vp != null) {
240
                return vp.setValue(watch, value);
241
            } else {
242
                return ValueProvider.super.setValue(watch, value);
243
            }
244
        }
245
246
        @Override
247
        public synchronized void setChangeListener(Watch watch, ValueChangeListener chl) {
248
            ValueProvider vp = delegate;
249
            if (vp != null) {
250
                vp.setChangeListener(watch, chl);
251
            }
252
            listeners.put(watch, chl);
253
        }
254
255
        @Override
256
        public synchronized void unsetChangeListener(Watch watch) {
257
            ValueProvider vp = delegate;
258
            if (vp != null) {
259
                vp.unsetChangeListener(watch);
260
            }
261
            listeners.remove(watch);
262
        }
263
        
264
        synchronized void setDelegate(ValueProvider delegate) {
265
            this.delegate = delegate;
266
            if (delegate == null) {
267
                for (Map.Entry<Watch, ValueChangeListener> wvl : listeners.entrySet()) {
268
                    wvl.getValue().valueChanged(wvl.getKey());
269
                }
270
            } else {
271
                for (Map.Entry<Watch, ValueChangeListener> wvl : listeners.entrySet()) {
272
                    delegate.setChangeListener(wvl.getKey(), wvl.getValue());
273
                }
274
            }
275
        }
276
        
277
    }
278
    
279
    /**
280
     * Provider of pinned watch value.
281
     * Register an implementation of this class via {@link DebuggerServiceRegistration}
282
     * for the corresponding debugger session ID path.
283
     */
284
    public static interface ValueProvider {
285
        
286
        /**
287
         * Get a unique ID of this value provider.
288
         * Use this ID when pinning a watch via {@link #pin(org.netbeans.api.debugger.Watch, java.lang.String)}.
289
         * @return An ID of this value provider.
290
         */
291
        String getId();
292
        
293
        /**
294
         * Get current value of pinned watch. This method must not block,
295
         * it's called synchronously in the EQ thread. This method should return
296
         * most recent value of the watch, or the same instance which
297
         * {@link #getEvaluatingText()} returns when the watch value is being computed,
298
         * or <code>null</code> when the watch can not be resolved.
299
         * @param watch the watch whose value is to be returned.
300
         * @return The current value of the watch, or {@link #getEvaluatingText()},
301
         *         or <code>null</code>.
302
         */
303
        String getValue(Watch watch);
304
        
305
        /**
306
         * Get a localized text to be displayed when the watch is being evaluated.
307
         * The pin watch UI highlights changed values. It uses this string to
308
         * distinguish real watch values. Return the same instance from
309
         * {@link #getValue(org.netbeans.api.debugger.Watch)} when the watch is
310
         * being computed.
311
         * @return A localized text displayed while the watch is evaluating.
312
         */
313
        @NbBundle.Messages("WATCH_EVALUATING=Evaluating...")
314
        default String getEvaluatingText() {
315
            return Bundle.WATCH_EVALUATING();
316
        }
317
318
        /**
319
         * Determine whether the current watch value is editable and if yes,
320
         * return the value to edit.
321
         * The value returned by {@link #getValue(org.netbeans.api.debugger.Watch)}
322
         * might not be the proper value to edit. It may contain type description
323
         * or more descriptive information about the value. This method should
324
         * provide a raw textual representation of the value to edit,
325
         * or <code>null</code> when the value is not editable.<br>
326
         * The default implementation return <code>null</code>.
327
         * @param watch The watch to return the editable value for
328
         * @return The string representation of the editable value,
329
         * or <code>null</code> when the value is not editable.
330
         */
331
        default String getEditableValue(Watch watch) {
332
            return null;
333
        }
334
335
        /**
336
         * Set a watch value as a response to finished editing.
337
         * This method is called only when a prior call to
338
         * {@link #getEditableValue(org.netbeans.api.debugger.Watch)} returns
339
         * a non-null value.<br>
340
         * The default implementation throws {@link UnsupportedOperationException}.
341
         * @param watch The watch to set the value for.
342
         * @param value The new watch value.
343
         * @return <code>true</code> when the value was set successfully and
344
         *         the UI should get updated from {@link #getValue(org.netbeans.api.debugger.Watch)},
345
         *         <code>false</code> when the set fails and the last watch value
346
         *         should stay. The implementation is responsible for any error
347
         *         reporting when the set fails.
348
         */
349
        default boolean setValue(Watch watch, String value) {
350
            throw new UnsupportedOperationException("Watch not editable.");
351
        }
352
353
        /**
354
         * Allows to set a value change listener for a specific watch.
355
         * @param watch The watch to listen for changes
356
         * @param chl The value change listener.
357
         */
358
        void setChangeListener(Watch watch, ValueChangeListener chl);
359
        
360
        /**
361
         * Unset a value change listener for a specific watch.
362
         * Use this method to unregister the listeners and free up associated resources.
363
         * @param watch The watch to unset the listener from.
364
         */
365
        void unsetChangeListener(Watch watch);
366
        
367
        /**
368
         * Listener for watch value changes.
369
         */
370
        public static interface ValueChangeListener {
371
            
372
            /**
373
             * Notify that a watch value has changed.
374
             * {@link ValueProvider#getValue(org.netbeans.api.debugger.Watch)}
375
             * then returns the new value.
376
             * @param watch The watch whose value has changed.
377
             */
378
            void valueChanged(Watch watch);
379
        }
380
    }
381
}

Return to bug 258651