Source code file content

Revision: 2

import
» Project Revision History

» Checkout URL

web-content / trunk / docs / navigator-tutorial / tutorial.html

Size: 22118 bytes, 1 line
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<HTML>
<HEAD>
	<META HTTP-EQUIV="CONTENT-TYPE" CONTENT="text/html; charset=iso-8859-1">
	<TITLE>C/C++ language model API tutorial. Create C/C++ Navigator.</TITLE>
	<META NAME="GENERATOR" CONTENT="StarOffice 7  (Solaris x86)">
	<META NAME="AUTHOR" CONTENT="Alexander Simon">
</HEAD>
<link rel="stylesheet" type="text/css" href="http://www.netbeans.org/netbeans.css">
<BODY LANG="en-US" DIR="LTR">

<h1>C/C++ Pack, Language Model and C/C++ Navigator Tutorial</h1>

<p>In this tutorial, you will learn how to create a BeanTreeView navigator based on C/C++ language model.
<p>Once this tutorial is finished, you will have a BeanTreeView navigator that provides structure of currently edited C/C++ file.

<p><h2><a name="gettingtoknowthesample"></a>Creating module and navigator view.</h2>

<ol>
<p><li>Choose File &gt; New Project. In the New Project wizard, choose
<tt>NetBeans Plug-in Modules</tt> under Categories and <tt>Module Project</tt>
under Projects. Click Next. Type <tt>CppNavigatorTreeView</tt> in
Project Name and set Project Location to an appropriate folder on
your disk. If they are not selected, select Standalone Module and Set
as Main Project. Click Next.

<p><li>Type <tt>org.netbeans.mycppextension</tt> in Code Name Base and <tt>C/C++
Navigator Tree View</TT> in Module Display Name. Click Finish.
<p><li>Right-click the project, choose Properties, click
Libraries in the Project Properties dialog box and declare a
dependency on the following APIs: 
<P><UL>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-actions/overview-summary.html">
            <FONT COLOR="#3333ff">Actions API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-explorer/overview-summary.html">
            <FONT COLOR="#3333ff">Explorer and Property Sheet API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-nodes/overview-summary.html">
            <FONT COLOR="#3333ff">Nodes API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="../org-netbeans-modules-cnd-api-model/overview-summary.html">
            <FONT COLOR="#3333ff">C/C++ Code Model API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-loaders/overview-summary.html">
            <FONT COLOR="#3333ff">Datasystems API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-netbeans-modules-editor/overview-summary.html">
            <FONT COLOR="#3333ff">Editor</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-netbeans-modules-editor-lib/overview-summary.html">
            <FONT COLOR="#3333ff">Editor Library</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-filesystems/overview-summary.html">
            <FONT COLOR="#3333ff">File System API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-text/overview-summary.html">
            <FONT COLOR="#3333ff">Text API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-awt/overview-summary.html">
            <FONT COLOR="#3333ff">UI Utilites API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-util/overview-summary.html">
            <FONT COLOR="#3333ff">Utilites API</FONT></A></P>
	<LI><P STYLE="margin-bottom: 0in"><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-windows/overview-summary.html">
            <FONT COLOR="#3333ff">Windows System API</FONT></A></P>
</UL>
<p><li>Right-click the project, choose Properties, click
Libraries in the Project Properties dialog box and declare a
dependency on the Non-API module (check <tt>Show Non-API Modules</tt>): 
<P><UL>
	<LI><P STYLE="margin-bottom: 0in">
            <FONT COLOR="#3333ff">C/C++ Code Model Utilities</FONT></P>
</UL>
<p>Edit <tt>C/C++ Code Model Utilities</tt> module dependency.
Set <tt>Imlpementation version</tt>.
In future module will be added in API.

<p><li>Right-click the module project, choose New &gt; File/Folder and
choose <tt>Window Component</tt> from the <tt>NetBeans Module Development</tt>
category. Click Next. Choose <TT>navigator</TT> in the
drop-down list and select Open on Application Start. Click Next.

<p><li>Type <TT>CppNavigator</TT> in Class Name Prefix. Optionally,
add an icon with a dimension of 16x16 pixels. Click Finish.

<p><li>Open <TT>CppNavigatorTopComponent.java</TT> in the Design view.
Right-click in the TopComponent, choose Set Layout, and select
BorderLayout.

<p><li>Use the Palette (Ctrl-Shift-8) to drop a
<TT>JScrollPane</TT> on <TT>CppNavigatorTopComponent.java</TT>.
Right-click the <TT>JScrollPane</TT>, choose Change
Variable Name and type <TT>navigatorPane</TT>.

<p><li>Open the Inspector, if it isn't open. (Use the Window menu.) In the Inspector,
select the <TT>navigatorPane</TT>, open the Properties window
(Ctrl-Shift-7), click the &quot;Code&quot; tab, and add this line to
the Custom Creation Code property (the very last property in the
list): 
<p><pre class="examplecode">
    new <a href="http://www.netbeans.org/download/dev/javadoc/org-openide-explorer/org/openide/explorer/view/BeanTreeView.html">BeanTreeView()</a>;
</pre>
<P>BeanTreeView is one of several views provided by the Explorer and
Property Sheet API.

<p><li>Click the Source toggle button in the GUI Builder. Right-click
in the Source Editor, and choose Fix imports (Alt-Shift-F). The dependency you set
on &quot;Explorer and Property Sheet API&quot; will cause the import
statement for the BeanTreeView being generated for you by the
IDE.

<p><li>In the <TT>Bundle.properties</TT> file, change the
<tt>CTL_CppNavigatorTopComponent</tt> and <tt>CTL_CppNavigatorAction</tt> keys to the
value <tt>C/C++ Navigator</tt>.

<p><li>Right-click the project
node and choose <tt>Install/Reload in Development IDE</tt>. If a
warning message appears, click OK. When the module installs, look
under the Window menu and you will find a new menu item called <tt>C/C++
Navigator</tt>, at the top of the list of menu items. Choose it and
you will see the start of your navigator view.
</ol>

<!-- ===================================================================================== -->

<p><h2><a name="gettingtoknowthesample"></a>Setup an explorer manager.</h2>

<ol>
<p><li>Open the <TT>CppnavigatorTopComponent.java</TT> in the Source view and add
<TT>implements ExplorerManager.Provider</TT> to the signature at the
top of the class.

<p><li>Next, instantiate the <TT><A HREF="http://www.netbeans.org/download/dev/javadoc/org-openide-explorer/org/openide/explorer/ExplorerManager.html">ExplorerManager</A></TT>
as a transient object: 
<p><pre class="examplecode">
    private transient ExplorerManager explorerManager = new ExplorerManager();
</PRE>

<p><li>Place the cursor in the signature. A light bulb will prompt you to
let the IDE insert an import statement and implement the abstract
methods. Follow its advice, by clicking on the suggestion, and then
fill out the generated <TT>getExplorerManager()</TT> as follows: 
<p><pre class="examplecode">
        public ExplorerManager getExplorerManager() {
             return explorerManager;
        }
</PRE>

<p><li>Create field:
<p><pre class="examplecode">
        private AbstractNode root;
</PRE>

<p><li>Now go to the Constructor and add the following after the last existing line:
<p><pre class="examplecode">
        ((BeanTreeView)navigatorPane).setRootVisible(false);
        Children.Array children = new Children.SortedArray();
        root = new AbstractNode(children);
        getExplorerManager().setRootContext(root);
</PRE>

<p><li>Fix imports. Select <tt>org.openide.nodes.Children</tt> for <tt>Children</tt>.

</ol>

<!-- ===================================================================================== -->

<p><h2><a name="gettingtoknowthesample"></a>Create node and nodes support.</h2>
<p>Create class called <tt>CppDeclarationNode.java</tt> and add following content:
<p><pre class="examplecode">
import java.awt.Image;
import java.awt.event.ActionEvent;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Iterator;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.netbeans.modules.cnd.api.model.CsmClass;
import org.netbeans.modules.cnd.api.model.CsmClassifier;
import org.netbeans.modules.cnd.api.model.CsmDeclaration;
import org.netbeans.modules.cnd.api.model.CsmEnum;
import org.netbeans.modules.cnd.api.model.CsmEnumerator;
import org.netbeans.modules.cnd.api.model.CsmFunction;
import org.netbeans.modules.cnd.api.model.CsmInclude;
import org.netbeans.modules.cnd.api.model.CsmMacro;
import org.netbeans.modules.cnd.api.model.CsmMember;
import org.netbeans.modules.cnd.api.model.CsmNamespaceDefinition;
import org.netbeans.modules.cnd.api.model.CsmObject;
import org.netbeans.modules.cnd.api.model.CsmOffsetable;
import org.netbeans.modules.cnd.api.model.CsmParameter;
import org.netbeans.modules.cnd.api.model.CsmType;
import org.netbeans.modules.cnd.api.model.util.CsmKindUtilities;
import org.netbeans.modules.cnd.modelutil.AbstractCsmNode;
import org.netbeans.modules.cnd.modelutil.CsmUtilities;
import org.openide.nodes.Children;
import org.openide.util.Utilities;

/**
 * Navigator Tree node.
 */
public class CppDeclarationNode extends AbstractCsmNode implements Comparable {
    private Image icon;
    private CsmObject object;
    private CppDeclarationNode(CsmObject element) {
        super(new NavigatorChildren(element));
        object = element;
    }
    
    private CppDeclarationNode(Children children, CsmObject element) {
        super(children);
        object = element;
    }

    public CsmObject getCsmObject() {
        return object;
    }
    
    public int compareTo(Object o) {
        if( o instanceof CppDeclarationNode ) {
            return getDisplayName().compareTo(((CppDeclarationNode) o).getDisplayName());
        }
        return 0;
    }
    
    public void setIcon(Image icon) {
        this.icon = icon;
    }
    
    public Image getIcon(int param) {
        if (icon != null){
            return icon;
        }
        return super.getIcon(param);
    }
    
    public Image getOpenedIcon(int param) {
        return getIcon(param);
    }
    
    public Action getPreferredAction() {
        if (CsmKindUtilities.isOffsetable(object)){
            return new AbstractAction(){
                public void actionPerformed(ActionEvent e) {
                    CsmUtilities.openSource((CsmOffsetable)object);
                }
            };
        }
        return super.getPreferredAction();
    }
    
    public static CppDeclarationNode nodeFactory(CsmObject element){
        CppDeclarationNode node = null;
        if (CsmKindUtilities.isClassifier(element)){
            node = new CppDeclarationNode(element);
            node.setName(((CsmClassifier)element).getName());
        } else if(CsmKindUtilities.isNamespaceDefinition(element)){
            node = new CppDeclarationNode(element);
            node.setName(((CsmNamespaceDefinition)element).getName());
        } else if(CsmKindUtilities.isDeclaration(element)){
            node = new CppDeclarationNode(Children.LEAF,element);
            node.setName(((CsmDeclaration)element).getName());
            if(CsmKindUtilities.isFunction(element)){
                node.setName(getSignature((CsmFunction)element));
            } else {
                node.setName(((CsmDeclaration)element).getName());
            }
        } else if(CsmKindUtilities.isEnumerator(element)){
            node = new CppDeclarationNode(Children.LEAF,element);
            node.setName(((CsmEnumerator)element).getName());
        } else if(CsmKindUtilities.isMacro(element)){
            node = new CppDeclarationNode(Children.LEAF,element);
            node.setName(((CsmMacro)element).getName());
            node.setIcon(Utilities.loadImage("org/netbeans/mycppextension/cppnavigatortreeview/directive.png", true));
        } else if(element instanceof CsmInclude){
            node = new CppDeclarationNode(Children.LEAF,element);
            node.setName(((CsmInclude)element).getIncludeName());
            node.setIcon(Utilities.loadImage("org/netbeans/mycppextension/cppnavigatortreeview/directive.png", true));
        }
        return node;
    }
    
    private static String getSignature(CsmFunction fun) {
        StringBuffer sb = new StringBuffer(fun.getName());
        sb.append('(');
        boolean addComma = false;
        for( Iterator iter = fun.getParameters().iterator(); iter.hasNext(); ) {
            CsmParameter par = (CsmParameter) iter.next();
            if( addComma ) {
                sb.append(", ");
            } else {
                addComma = true;
            }
            CsmType type = par.getType();
            if( type != null ) {
                sb.append(type.getText());
                sb.append(' ');
            }
            sb.append(par.getName());
        }
        sb.append(')');
        return sb.toString();
    }

    private static class NavigatorChildren extends Children.SortedArray {
        private CsmObject element;
        public NavigatorChildren(CsmObject element){
            this.element = element;
        }
        
        protected Collection initCollection() {
            Collection retValue = new ArrayList();
            if (CsmKindUtilities.isClass(element)){
                CsmClass cls = (CsmClass)element;
                for (Iterator it = cls.getMembers().iterator(); it.hasNext();){
                    CppDeclarationNode node = nodeFactory((CsmMember)it.next());
                    if (node != null){
                        retValue.add(node);
                    }
                }
            } else if (CsmKindUtilities.isEnum(element)){
                CsmEnum cls = (CsmEnum)element;
                for (Iterator it = cls.getEnumerators().iterator(); it.hasNext();){
                    CppDeclarationNode node = nodeFactory((CsmEnumerator)it.next());
                    if (node != null){
                        retValue.add(node);
                    }
                }
            } else if(CsmKindUtilities.isNamespaceDefinition(element)){
                CsmNamespaceDefinition ns = (CsmNamespaceDefinition)element;
                for (Iterator it = ns.getDeclarations().iterator(); it.hasNext();){
                    CppDeclarationNode node = nodeFactory((CsmDeclaration)it.next());
                    if (node != null){
                        retValue.add(node);
                    }
                }
            }
            return retValue;
        }
    }
}
</PRE>
<p>Class extends <tt>AbstractCsmNode</tt> and override methods:
<p><pre class="examplecode">
    getIcon(int) {
    getOpenedIcon(int)
    getPreferredAction()
</PRE>
<p>Method <tt>getPreferredAction()</tt> uses implementation of module 
<tt>C/C++ Code Model Utilities</tt> to open model element in editor.
<p>Also class implements Comparable interface. 
Classifier and name space nodes use Children.SortedArray for children array.
Comparable interface allow sorting nodes by name.
<p>Inner class NavigatorChildren extends Children.SortedArray and is used for children array. Class override method:
<p><pre class="examplecode">
    protected Collection initCollection()
</PRE>
<p>Method responsible for lazy filling classes and name spaces nodes' content.
<p>Both class <tt>CppDeclarationNode</tt> constructors are private. Static factory method <tt>nodeFactory(CsmObject)</tt>
is responsible for node creation.

<!-- ===================================================================================== -->
<p><h2><a name="gettingtoknowthesample"></a>C/C++ language support.</h2>
Modify class <tt>CppNavigatorTopComponent</tt>.
<ol>
<p><li>Add in implements list two interfaces:
<p><pre class="examplecode">
        PropertyChangeListener, <A HREF="../org-netbeans-modules-cnd-api-model/org/netbeans/modules/cnd/api/model/CsmModelListener.html">CsmModelListener</A> 
</PRE>
<p>and implements abstract methods.

<p><li>Create field that will keep model file:
<p><pre class="examplecode">
    private <A HREF="../org-netbeans-modules-cnd-api-model/org/netbeans/modules/cnd/api/model/CsmFile.html">CsmFile</A> csmFile;
</PRE>

<p><li>At first we needed register and unregister component and model listeners. Replace methods:
<p><pre class="examplecode">
    public void componentOpened() {
        TopComponent.getRegistry().addPropertyChangeListener(this);
        CsmModelAccessor.getModel().addModelListener(this);
        checkNodes();
    }
    
    public void componentClosed() {
        TopComponent.getRegistry().removePropertyChangeListener(this);
        CsmModelAccessor.getModel().removeModelListener(this);
        setFile(null);
    }
</PRE>

<p><li>Create private methods that find model file by active node:
<p><pre class="examplecode">
    private void checkNodes(){
        checkNodes(TopComponent.getRegistry().getCurrentNodes());
    }
    
    private void checkNodes(Node[] arr){
        if (arr != null) {
            for (int j = 0; j < arr.length; j++) {
                CsmFile file = CsmUtilities.getCsmFile(arr[j],false);
                if (file != null)
                    setFile(file);
            }
        }
    }
</PRE>
<p>Method <tt>checkNodes()</tt> uses implementation of module 
<tt>C/C++ Code Model Utilities</tt> to find model file by node.

<p><li>Create methods that setup navigator content:
<p><pre class="examplecode">
    private void setFile(CsmFile file) {
        if (csmFile != file){
            csmFile = file;
            update();
        }
    }
    
    private synchronized void update() {
        if (csmFile != null){
            final Children children = root.getChildren();
            if (!children.MUTEX.isReadAccess()){
                children.MUTEX.writeAccess(new Runnable(){
                    public void run() {
                        children.remove(children.getNodes());
                        for(Iterator it = csmFile.getIncludes().iterator(); it.hasNext();){
                            CsmInclude element = (CsmInclude)it.next();
                            Node node = CppDeclarationNode.nodeFactory((CsmObject)element);
                            if (node != null){
                                children.add(new Node[]{node});
                            }
                        }
                        for(Iterator it = csmFile.getMacros().iterator(); it.hasNext();){
                            CsmMacro element = (CsmMacro)it.next();
                            Node node = CppDeclarationNode.nodeFactory((CsmObject)element);
                            if (node != null){
                                children.add(new Node[]{node});
                            }
                        }
                        for(Iterator it = csmFile.getDeclarations().iterator(); it.hasNext();){
                            CsmDeclaration element = (CsmDeclaration)it.next();
                            Node node = CppDeclarationNode.nodeFactory((CsmObject)element);
                            if (node != null){
                                children.add(new Node[]{node});
                            }
                        }
                    }
                });
            }
        } else {
            final Children children = root.getChildren();
            if (!children.MUTEX.isReadAccess()){
                children.MUTEX.writeAccess(new Runnable(){
                    public void run() {
                        children.remove(children.getNodes());
                    }
                });
            }
        }
    }
</PRE>
<p>Method <tt>update()</tt> refreshes navigator tree.
Method passes through model file include directives, macros and declarations.

<p><li>Add component support. Replace method:
<p><pre class="examplecode">
    public void propertyChange(PropertyChangeEvent evt) {
        if (TopComponent.Registry.PROP_ACTIVATED.equals(evt.getPropertyName())){
            checkNodes();
        }
    }
</PRE>

<p><li>Add Model support. Replace methods:
<p><pre class="examplecode">
    public void projectOpened(CsmProject project) {
            checkNodes();
    }
    
    public void projectClosed(CsmProject project) {
        if (csmFile != null){
            if (csmFile.getProject() == project){
                setFile(null);
            }
        }
    }
    
    public void modelChanged(<A HREF="../org-netbeans-modules-cnd-api-model/org/netbeans/modules/cnd/api/model/CsmChangeEvent.html">CsmChangeEvent</A> e) {
        if (csmFile != null){
            if (e.getChangedFiles().contains(csmFile)){
                update();
            }
        } else {
            checkNodes();
        }
    }
</PRE>

<p><li>Fix imports. Select <tt>java.itil.Iterator</tt> for <tt>Iterator</tt> and 
<tt>org.openide.nodes.Node</tt> for <tt>Node</tt>.


<p><li>Save icon:
<p>
<IMG SRC="directive.png" NAME="directive" ALIGN=BOTTOM WIDTH=16 HEIGHT=16 BORDER=0>
<p>with name <tt>directive.png</tt> in the package
<tt>org.netbeans.mycppextension.cppnavigatortreeview</tt>.

<p><li>Right-click the project node and choose <tt>Install/Reload in Development IDE</tt>.
Open C/C++ project. You can see edited file declarations in C/C++ Navigator:
</ol>

<IMG SRC="api.jpg" NAME="using C/C++ model API" ALIGN=BOTTOM BORDER=0><BR><BR>

<!-- ===================================================================================== -->

<p><h2><a name="gettingtoknowthesample"></a>Downloads</h2>
<p>Download <a href="CppNavigatorTreeView.zip">NetBeans Project</a> or 
<a href="org-netbeans-mycppextension-cppnavigatortreeview.nbm">NetBeans Module</a>.
</BODY>
</HTML>

Project Features

About this Project

CND was started in November 2009, is owned by DimaZh, and has 197 members.
By use of this website, you agree to the NetBeans Policies and Terms of Use (revision 20160708.bf2ac18). © 2014, Oracle Corporation and/or its affiliates. Sponsored by Oracle logo
 
 
Close
loading
Please Confirm
Close