diff -r 94c11ec6a4c3 spi.debugger.ui/manifest.mf --- a/spi.debugger.ui/manifest.mf Mon Dec 23 15:48:03 2013 +0000 +++ b/spi.debugger.ui/manifest.mf Sun Jan 05 21:45:40 2014 +0100 @@ -2,6 +2,6 @@ OpenIDE-Module: org.netbeans.spi.debugger.ui/1 OpenIDE-Module-Localizing-Bundle: org/netbeans/modules/debugger/ui/Bundle.properties OpenIDE-Module-Layer: org/netbeans/modules/debugger/resources/mf-layer.xml -OpenIDE-Module-Specification-Version: 2.41 +OpenIDE-Module-Specification-Version: 2.42 OpenIDE-Module-Provides: org.netbeans.spi.debugger.ui OpenIDE-Module-Install: org/netbeans/modules/debugger/ui/DebuggerModule.class diff -r 94c11ec6a4c3 spi.debugger.ui/src/org/netbeans/spi/debugger/ui/DebuggingView.java --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/spi.debugger.ui/src/org/netbeans/spi/debugger/ui/DebuggingView.java Sun Jan 05 21:45:40 2014 +0100 @@ -0,0 +1,626 @@ +/* + * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER. + * + * Copyright 2013 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 2013 Sun Microsystems, Inc. + */ + +package org.netbeans.spi.debugger.ui; + +import java.awt.Image; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; +import java.beans.PropertyChangeSupport; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; +import java.lang.ref.Reference; +import java.lang.ref.WeakReference; +import java.util.Collection; +import java.util.LinkedList; +import java.util.List; +import java.util.Set; +import java.util.prefs.Preferences; +import javax.swing.Action; +import javax.swing.Icon; +import org.netbeans.api.debugger.Breakpoint; +import org.netbeans.api.debugger.Session; +import org.netbeans.modules.debugger.ui.views.debugging.DebuggingViewComponent; +import org.netbeans.modules.debugger.ui.views.debugging.FiltersDescriptor; +import org.netbeans.modules.debugger.ui.views.debugging.FiltersDescriptor.FilterImpl; +import org.netbeans.modules.debugger.ui.views.debugging.FiltersDescriptor.FiltersAccessor; +import org.openide.windows.TopComponent; + +/** + * Debugging view component provider. The debugging view displays application threads. + * Implement {@link DVSupport} and register under your session name to use + * debugging view UI and register appropriate view models for path <session name>/DebuggingView. + * + * @author Martin Entlicher + * @since 2.42 + */ +public final class DebuggingView { + + private final static DebuggingView INSTANCE = new DebuggingView(); + + private Reference dvcRef = new WeakReference(null); + + private DebuggingView() { + //this.dvc = DebuggingViewComponent.getInstance(); + } + + /** + * Get the default implementation of debugging view provider. + * @return the default instance of debugging view provider. + */ + public static DebuggingView getDefault() { + return INSTANCE; + } + + private DebuggingViewComponent getDVC() { + DebuggingViewComponent dvc; + synchronized (this) { + dvc = dvcRef.get(); + if (dvc == null) { + dvc = DebuggingViewComponent.getInstance(); + dvcRef = new WeakReference(dvc); + } + } + return dvc; + } + + /** + * Get the debugging view top component. + * @return the {@link TopComponent} of the debugging view. + */ + public TopComponent getViewTC() { + return getDVC(); + } + + /** + * Support for debugging view. The component tree is created from view models + * registered under path <session name>/DebuggingView. But to fully + * support the debugging view UI, additional information is necessary. + * Implement this class to provide the additional information. + * Debugging view is created for the given debugger session only when an + * implementation of this class is found in the current session engine lookup. + */ + public static abstract class DVSupport { + + /** Property name constant. */ + public static final String PROP_THREAD_STARTED = "threadStarted"; // NOI18N + /** Property name constant. */ + public static final String PROP_THREAD_DIED = "threadDied"; // NOI18N + /** Property name constant. */ + public static final String PROP_THREAD_GROUP_ADDED = "threadGroupAdded"; // NOI18N + /** Property name constant. */ + public static final String PROP_THREAD_SUSPENDED = "threadSuspended"; // NOI18N + /** Property name constant. */ + public static final String PROP_THREAD_RESUMED = "threadResumed"; // NOI18N + /** Property name constant. */ + public static final String PROP_CURRENT_THREAD = "currentThread"; // NOI18N + + /** + * Name of property which is fired when deadlock occurs. + */ + public static final String PROP_DEADLOCK = "deadlock"; // NOI18N + public static final String PROP_STATE = "state"; // NOI18N + + private final PropertyChangeSupport pcs = new PropertyChangeSupport(this); + + /** + * The debugger state. + */ + public static enum STATE { + RUNNING, + DISCONNECTED + } + + static { + FiltersDescriptor.getInstance().setFiltersAccessor(new FiltersAccessor() { + @Override + public List getFilters(DVSupport dvs) { + return dvs.getFilters(); + } + @Override + public FilterImpl getImpl(DVFilter filter) { + return filter.getImpl(); + } + }); + } + + protected DVSupport() { + } + + /** + * Get the debugger state. + * @return current state of debugger + */ + public abstract STATE getState(); + + /** + * Get listing of all threads at this moment. + * @return list of all threads + */ + public abstract List getAllThreads(); + + /** + * Get a current thread, if any. + * @return a current thread, or null. + */ + public abstract DVThread getCurrentThread(); + + /** + * Get the display name of the thread. It can contain more information + * than a thread name, like current session name, etc. + * @param thread the thread + * @return the thread display name + */ + public abstract String getDisplayName(DVThread thread); + + /** + * Get the thread icon. + * @param thread the thread + * @return the thread icon + */ + public abstract Image getIcon(DVThread thread); + + /** + * Get the session associated with this debugging view. + * @return + */ + public abstract Session getSession(); + + /** + * Resume the application (all it's threads). + */ + public abstract void resume(); + + /** + * Get the set of detected deadlocks, if any. + * @return The set of deadlocks, or null when no deadlocks are detected. + */ + public abstract Set getDeadlocks(); + + /** + * Utility method used by the implementing class to create deadlock description instances. + * @param threads The threads in deadlock + * @return Deadlock instance + */ + protected final Deadlock createDeadlock(Collection threads) { + return new Deadlock(threads); + } + + /** + * Get the list of filters applied to debugging view. + * @return list of filters + */ + protected abstract List getFilters(); + + /** + * Get actions created from the provided filters. + * The result can be added to actions provider view model. + * @return filter actions. + */ + public final Action[] getFilterActions() { + return FiltersDescriptor.getInstance().getFilterActions(); + } + + protected final void firePropertyChange(PropertyChangeEvent pce) { + pcs.firePropertyChange(pce); + } + + /** + * Fire a property change event. + * @param propertyName the property name + * @param oldValue old value + * @param newValue new value + */ + protected final void firePropertyChange(String propertyName, Object oldValue, Object newValue) { + pcs.firePropertyChange(propertyName, oldValue, newValue); + } + + /** + * Add a property change listener. + * @param pcl the property change listener + */ + public final void addPropertyChangeListener(PropertyChangeListener pcl) { + pcs.addPropertyChangeListener(pcl); + } + + /** + * Remove a property change listener. + * @param pcl the property change listener + */ + public final void removePropertyChangeListener(PropertyChangeListener pcl) { + pcs.removePropertyChangeListener(pcl); + } + + /** + * Declarative registration of a DVSupport implementation. + * By marking the implementation class with this annotation, + * you automatically register that implementation for use by the debugging view. + * The class must be public and have a public constructor which takes + * no arguments or takes {@link ContextProvider} as an argument. + * + * @author Martin Entlicher + */ + @Retention(RetentionPolicy.SOURCE) + @Target({ElementType.TYPE}) + public @interface Registration { + /** + * The path to register this implementation in. + * Usually the session ID. + */ + String path(); + + /** + * An optional position in which to register this service relative to others. + * Lower-numbered services are returned in the lookup result first. + * Services with no specified position are returned last. + */ + int position() default Integer.MAX_VALUE; + + } + + } + + /** + * Representation of a thread in debugging view. + * Nodes representing a thread in debugging view model should implement this + * interface. + */ + public static interface DVThread { + + /** + * Property name fired when a thread gets suspended. + */ + public static final String PROP_SUSPENDED = "suspended"; // NOI18N + /** + * Property name fired when list of locker threads change. + */ + public static final String PROP_LOCKER_THREADS = "lockerThreads"; // NOI18N + /** + * Property name fired when current breakpoint is changed. + */ + public static final String PROP_BREAKPOINT = "currentBreakpoint"; // NOI18N + + /** + * Get the name of the thread. + * @return the name of the thread + */ + public String getName(); + + /** + * Test if this thread is currently suspended by debugger. + * @return true when the thread is suspended, false otherwise. + */ + public boolean isSuspended(); + + /** + * Resume this thread. + */ + public void resume(); + + /** + * Suspend this thread. + */ + public void suspend(); + + /** + * Make this thread current. Code evaluation and stepping should be performed + * in the current thread. + */ + public void makeCurrent(); + + /** + * Get the debugging view support that provides this thread. + * @return the debugging view support + */ + public DVSupport getDVSupport(); + + /** + * Lists threads that hold monitors that this thread is waiting on. + * @return list of locker threads + */ + public List getLockerThreads(); + + /** + * Resume any suspended threads that block execution of this thread by holding monitors. + */ + public void resumeBlockingThreads(); + + /** + * Get current breakpoint, if any. This is a breakpoint that this thread is suspended on. + * @return the current breakpoint or null + */ + public Breakpoint getCurrentBreakpoint(); + + /** + * Test if this thread is performing a step operation right now. + * @return true if this thread is in a step, false otherwise. + */ + public boolean isInStep(); + + /** + * Add a property change listener. + * @param pcl the property change listener + */ + public void addPropertyChangeListener(PropertyChangeListener pcl); + + /** + * Remove a property change listener. + * @param pcl the property change listener + */ + public void removePropertyChangeListener(PropertyChangeListener pcl); + + } + + /** + * Representation of a thread group in debugging view. + * Nodes representing a thread group in debugging view model should implement + * this interface. + */ + public static interface DVThreadGroup { + + /** + * Get the name of the thread group. + * @return the name of the thread group + */ + public String getName(); + + /** + * Get the parent thread group, if exists. + * @return the parent thread group or null if this thread group has no parent (root thread group). + */ + public DVThreadGroup getParentThreadGroup(); + + /** + * Get this thread group's threads. + * @return threads from this thread group + */ + public DVThread[] getThreads(); + + /** + * Get this thread group's thread groups. + * @return thread groups from this thread group + */ + public DVThreadGroup[] getThreadGroups(); + } + + /** + * Representation of a deadlock - one set of mutually deadlocked threads. + */ + public static final class Deadlock { + + private final Collection threads; + + private Deadlock(Collection threads) { + this.threads = threads; + } + + /** + * Get the threads in deadlock. + * @return The threads in deadlock. + */ + public Collection getThreads() { + return threads; + } + } + + /** + * Boolean state filter that is applied to the debugging view. + * It's icon is made visible in the debugging view bottom panel. + */ + public static final class DVFilter { + + /** + * Pre-defined default filters enumeration. + */ + public static enum DefaultFilter { + sortAlphabetic, + sortSuspend, + sortNatural, + showQualifiedNames, + showMonitors, + showSystemThreads, + showSuspendTable, + showThreadGroups, + showSuspendedThreadsOnly, + } + + private static final Group sortGroup = new Group(); + + /** + * Get an instance of a default filter. + * @param filter the default filter kind + * @return filter implementation + */ + public static DVFilter getDefault(DefaultFilter filter) { + FilterImpl fimpl = FilterImpl.createDefault(filter); + Group g; + switch (filter) { + case sortAlphabetic: + case sortNatural: + case sortSuspend: + g = sortGroup; + break; + default: + g = null; + } + fimpl.setGroup(g); + return new DVFilter(fimpl, g); + } + + /** + * Create a custom filter. + * @param name name of the filter + * @param displayName display name of the filter (visible in an action menu) + * @param tooltip tool-tip of the filter + * @param selectedIcon icon of the filter + * @param valuePrefs preferences which are asked for the filter value + * @param valuePrefKey key that is used to retrieve the filter value from preferences + * @param isSelectedDefault whether the filter should be selected by default when preferences do not contain the value + * @param group a filter group, can be null + * @return implementation of the filter + */ + public static DVFilter create(String name, String displayName, + String tooltip, Icon selectedIcon, + Preferences valuePrefs, String valuePrefKey, + boolean isSelectedDefault, Group group) { + FilterImpl fimpl = new FilterImpl(name, displayName, tooltip, selectedIcon, + valuePrefs, valuePrefKey, isSelectedDefault); + fimpl.setGroup(group); + return new DVFilter(fimpl, group); + } + + private final FilterImpl fimpl; + private final Group group; + + DVFilter (FilterImpl fimpl, Group group) { + this.fimpl = fimpl; + this.group = group; + group.add(this); + } + + private FilterImpl getImpl() { + return fimpl; + } + + /** + * Get the filter group. + * @return the filter group, or null when the filter has no group + */ + public Group getGroup() { + return group; + } + + /** + * Get the filter name. + * @return the filter name + */ + public String getName() { + return fimpl.getName(); + } + + /** + * Get the filter display name. + * @return the filter display name + */ + public String getDisplayName() { + return fimpl.getDisplayName(); + } + + /** + * Get the filter tooltip. + * @return the filter tooltip + */ + public String getTooltip() { + return fimpl.getTooltip(); + } + + /** + * Get the filter icon. + * @return the filter icon + */ + public Icon getIcon() { + return fimpl.getIcon(); + } + + /** + * Test if the filter is selected. + * @return whether the filter is selected right now + */ + public boolean isSelected() { + return fimpl.isSelected(); + } + + /** + * Set the filter as selected/unselected. + * @param state whether to select the filter + */ + public void setSelected(boolean state) { + fimpl.setSelected(state); + } + + /** + * Get the filter preferences. + * @return the preferences of this filter + */ + public Preferences getPreferences() { + return fimpl.getPreferences(); + } + + /** + * Get the preference key. + * @return key that is used to retrieve the filter value from preferences + */ + public String getPrefKey() { + return fimpl.getPrefKey(); + } + + /** + * The filter group. + */ + public static final class Group { + + private final List items = new LinkedList(); + + /** + * Create a new empty group. + */ + public Group() { + } + + void add(DVFilter filter) { + items.add(filter); + } + + /** + * Get list of filters in this group. + * @return list of filters + */ + public List getItems() { + return items; + } + } + + } + +}