Extend C/C++ Pack with Switch Source/Header files plug-in
In this tutorial, you will see how
easy to extend C/C++ Pack base functionality with feature requested
by community.
Once this tutorial is finished, you
will have action for quick switching between associated Source and
Header files (same name but different suffix). Action name will be
file-type sensitive, has associated shortcut and be presented by
short name in Go To submenu of editor's popup menu.

Creating test C++ application.
We need test application with source
and header files to test our plug-in. Let's create test C++ Application:
Choose
File > New Project. In the New Project wizard, choose C/C++
Development under Categories and C/C++ Application
under Projects. Click Next. Type SwitchTest in Project Name
and set Project Location to an appropriate folder on your disk.
Uncheck Set as Main Project. Click Finish.
In
Project View right click on Header Files to display context menu and
choose New->C++ Header File. In Wizard leave File Name as
newfile. Click Finish. newfile.h is created.
In Project View right click on
Source Files to display context menu and choose New->Empty C++
File. In Wizard leave File Name as newfile. Click Finish.
newfile.cc is created.
Creating Netbeans plug-in Module and Action.
Choose File > New Project. In
the New Project wizard, choose NetBeans Plug-in Modules
under Categories and Module Project under Projects. Click
Next. Type CppSwitchFiles 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.
Type
org.netbeans.modules.cppswitchfiles in Code Name Base.
Click Finish.
Right-click the module project,
choose New > File/Folder and choose Action... from the
context menu.
In Wizard choose Action Type as
Conditionally Enabled. Leave selected User Selects One Node and Cookie Class as DataObject
-
Click Next and update GUI Registration. Change Category to Edit and
Menu to Navigate:
Click Next. Change Class Name to
CppSwitchAction and Display Name to C/C++
Switch Files. Click Finish.
Right-click the module project,
choose Properties, click Display. Change Display Name to C/C++
Switch Files and Display Category to C/C++. Click OK.
As result our projects look like:
First Review
Right-click the “C/C++ Switch
Files” project node and choose Install/Reload in
Development IDE. If a warning message appears, click OK. You can alway uninstall module using Tools->Module Manager Category C/C++
You can see new menu item in Navigate menu:
Implementing Switch Files Action.
Add Libraries dependency
Right-click the project, choose
Properties, click Libraries in the Project Properties dialog box and
declare a dependency on the following APIs:
Nodes
API
C/C++ Core
Datasystems
API
File
System API
Utilites
API
Configure
enable state of action
Enable action only for Header and
Source C/C++ files. Change cookieClasses() method (use Alt+Shift+F to
fix imports):
protected Class[] cookieClasses() {
return new Class[] {
HDataObject.class, CDataObject.class, CCDataObject.class
};
}
Add utilities to find file where to switch
In activated nodes look for Source or
Header file and find associated Header or Source.
private FileObject findToggleFile(final Node[] activatedNodes) {
FileObject res = null;
// check whether current file is C++ Source file
DataObject dob = (CCDataObject) activatedNodes[0].getLookup().lookup(CCDataObject.class);
if (dob == null) {
// check whether current file is C Source file
dob = (CDataObject) activatedNodes[0].getLookup().lookup(CDataObject.class);
}
if (dob != null) {
// it was Source file, find Header
res = findBrother(dob, getSuffices(HDataLoader.getInstance().getExtensions()));
} else {
// check whether current file is Header file
dob = (HDataObject) activatedNodes[0].getLookup().lookup(HDataObject.class);
if (dob != null) {
// try to find C++ Source file
res = findBrother(dob, getSuffices(CCDataLoader.getInstance().getExtensions()));
if (res == null) {
// try to find C Source file
res = findBrother(dob, getSuffices(CDataLoader.getInstance().getExtensions()));
}
}
}
return res;
}
private FileObject findBrother(DataObject dob, String[] ext) {
assert (dob != null);
assert (dob.getPrimaryFile() != null);
// get a file object associated with the data object
FileObject fo = dob.getPrimaryFile();
if (ext != null && ext.length > 0) {
// try to find a file with the same name and one of passed extensions
for (int i = 0; i < ext.length; i++) {
// use FileUtilities to find brother of the file object
FileObject res = FileUtil.findBrother(fo, ext[i]);
if (res != null) {
return res;
}
}
}
return null;
}
private static String[] getSuffices(ExtensionList list) {
List suffixes = new ArrayList();
for (Enumeration e = list.extensions(); e != null && e.hasMoreElements();) {
String ex = (String) e.nextElement();
suffixes.add(ex);
}
return (String[])suffixes.toArray(new String[suffixes.size()]);
}
Implement method to open file in editor
private void doToggle(final FileObject fo) {
assert (fo != null);
try {
// find a data object for the input file object
DataObject toggled = DataObject.find(fo);
if (toggled != null) {
// check if the data object has possibility to be opened in editor
final OpenCookie oc = (OpenCookie)toggled.getCookie(OpenCookie.class);
if (oc != null) {
// try to open ASAP, but better not in EQ
RequestProcessor.getDefault().post(new Runnable() {
public void run() {
// open component
oc.open();
}
}, 0, Thread.MAX_PRIORITY);
}
}
} catch (DataObjectNotFoundException ex) {
// may be error message?
}
}
Implement performAction
Change performAction() method to find
file where to switch:
protected void performAction(Node[] activatedNodes) {
// find file where to switch
FileObject res = findToggleFile(activatedNodes);
if (res != null) {
doToggle(res);
}
}
Use Action
Right-click the “C/C++ Switch
Files” project node and choose Install/Reload in
Development IDE. Open newfile.cc or newfile.h and try
Navigate->C/C++ Switch File menu item. Files will be switched
(opened if necessary).
Improve Usability - I
In this part we plan to introduce
shortcut Ctrl+Shift+A for our action and put it in C/C++ editor context
menu.
Register shortcut for the Action
Open layer.xml file and add following
on filesystem level:
<filesystem>
...
<folder name="Shortcuts">
<file name="DS-A.shadow">
<attr name="originalFile" stringvalue="Actions/Edit/org-netbeans-modules-cppswitchfiles-CppSwitchAction.instance"/>
</file>
</folder>
...
</filesystem>
Register Action in editor context menu
Open layer.xml file and add following
on filesystem level for C and C++ languages:
<filesystem>
...
<folder name="Editors">
<folder name="text">
<folder name="x-c++">
<folder name="Popup">
<folder name="goto">
<file name="org-netbeans-modules-cppswitchfiles-CppSwitchAction .shadow">
<attr name="originalFile" stringvalue="Actions/Edit/org-netbeans-modules-cppswitchfiles-CppSwitchAction.instance"/>
</file>
</folder>
</folder>
</folder>
<folder name="x-c">
<folder name="Popup">
<folder name="goto">
<file name="org-netbeans-modules-cppswitchfiles-CppSwitchAction.shadow">
<attr name="originalFile" stringvalue="Actions/Edit/org-netbeans-modules-cppswitchfiles-CppSwitchAction.instance"/>
</file>
</folder>
</folder>
</folder>
</folder>
</folder>
...
</filesystem>
Use Action
Right-click the “C/C++ Switch
Files” project node and choose Install/Reload in
Development IDE. Open newfile.cc or newfile.h and try Ctrl+Shift+A.
Files will be switched. Make sure context menu has added action.

Improve Usability -
II
In this part we plan to make our
action consistent with Netbeans infrastructure and make it file-type
sensitive.
Add Libraries dependency
Right-click the project, choose
Properties, click Libraries in the Project Properties dialog box and
declare a dependency on the Editor
Library.
Remember caret positions
To have possibility to go back/forward
between caret positions with Alt+K/Alt+L update doToggle method:
private void doToggle(final FileObject fo) {
...
if (oc != null) {
// remember current caret position
JTextComponent textComponent = Registry.getMostActiveComponent();
JumpList.checkAddEntry(textComponent);
// try to open ASAP, but better not in EQ
...
}
Change Action name to be file type
sensitive
By Netbeans convetions Go To submenu uses trimmed
name for menu items (Line... instead of Go to Line...) and we will add the same support for our action.
Also let's make action name to be file type sensitive.
Update Bundle.properties:
CTL_CppSwitchAction=C/C++ Switch Files
OpenIDE-Module-Display-Category=C/C++
OpenIDE-Module-Name=C/C++ Switch Files
#names for Navigate menu
CppGoToSourceFileAction=C/C++ Switch to Source File
CppGoToHeaderFileAction=C/C++ Switch to Header File
#short names for Go To popup submenu
goto-cpp-switch-file=Source/Header File
goto-cpp-source-file=&Source File
goto-cpp-header-file=&Header File
Change CppSwitchAction
Add necessary support in
CppSwitchAction to handle file-type. Update action name in Navigate
menu and editor context submenu to be file-type sensitive:
public String getName() {
String trimmedNameKey = "goto-cpp-switch-file"; //NOI18N
String fullNameKey = "CTL_CppSwitchAction"; //NOI18N
if (isEnabled()) {
switch (getToggleInfo(getActivatedNodes())) {
case NodeKind.HEADER:
trimmedNameKey = "goto-cpp-header-file"; //NOI18N
fullNameKey = "CppGoToHeaderFileAction"; //NOI18N
break;
case NodeKind.SOURCE:
trimmedNameKey = "goto-cpp-source-file"; //NOI18N
fullNameKey = "CppGoToSourceFileAction"; //NOI18N
break;
}
}
String trimmedName = NbBundle.getMessage(CppSwitchAction.class, trimmedNameKey);;
putValue(ExtKit.TRIMMED_TEXT, trimmedName);
putValue(BaseAction.POPUP_MENU_TEXT, trimmedName);
return NbBundle.getMessage(CppSwitchAction.class, fullNameKey);
}
private static final class NodeKind {
private static final int HEADER = 1;
private static final int SOURCE = 2;
private static final int NONE = 0;
}
private int getToggleInfo(Node[] activatedNodes) {
if (activatedNodes != null && activatedNodes.length == 1) {
if (activatedNodes[0].getLookup().lookup(HDataObject.class) != null) {
return NodeKind.SOURCE;
} else if (activatedNodes[0].getLookup().lookup(CCDataObject.class) != null ||
activatedNodes[0].getLookup().lookup(CDataObject.class) != null) {
return NodeKind.HEADER;
}
}
return NodeKind.NONE;
}
Use Action
Right-click the “C/C++ Switch
Files” project node and choose Install/Reload in
Development IDE. Open newfile.cc or newfile.h, make sure context
menu has short name for action. Also check, that name is file-type
sensitive.

Downloads
Download sources of the tutorial or result nbm files.