Skip to content

Commit

Permalink
Merge pull request apache#6441 from bitrunner/cnd-revive-go-to-header…
Browse files Browse the repository at this point in the history
…-source

[cnd] revive go to header/source action from cnd.navigation
  • Loading branch information
vieiro authored Oct 9, 2023
2 parents 760d66d + 17e74f5 commit 8272f00
Show file tree
Hide file tree
Showing 5 changed files with 299 additions and 0 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -140,3 +140,13 @@ CND_Other_Display_Name=Other

select-element-next=Select Next Element
select-element-previous=Select Previous Element

Actions/Edit/org-netbeans-modules-cnd-editor-cplusplus-CppSwitchAction.instance=Go to Header/Source

goto-cpp-source-file=Go to &Source
goto-cpp-header-file=Go to &Header
goto-cpp-switch-file=Go to Header/&Source
cpp-switch-file-not-found=No suitable source or header file has been found
cpp-switch-header-not-found=No suitable source file has been found
cpp-switch-source-not-found=No suitable header file has been found
cpp-switch-header-source=Go to Header/Source
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/

package org.netbeans.modules.cnd.editor.cplusplus;

import java.awt.event.ActionEvent;
import java.util.Collection;
import javax.swing.text.JTextComponent;
import org.netbeans.api.editor.EditorRegistry;
import org.netbeans.editor.BaseAction;
import org.netbeans.editor.JumpList;
import org.netbeans.modules.cnd.utils.MIMEExtensions;
import org.netbeans.modules.cnd.utils.MIMENames;
import org.netbeans.modules.cnd.utils.cache.CndFileUtils;
import org.openide.awt.StatusDisplayer;
import org.openide.cookies.OpenCookie;
import org.openide.filesystems.FileObject;
import org.openide.filesystems.FileUtil;
import org.openide.loaders.DataObject;
import org.openide.loaders.DataObjectNotFoundException;
import org.openide.nodes.Node;
import org.openide.util.NbBundle;
import org.openide.util.RequestProcessor;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;

public final class CppSwitchAction extends BaseAction {

private static final String ACTION_NAME = "cpp-switch-header-source"; // NOI18N
private static final String ICON = "org/netbeans/modules/cnd/editor/resources/cplusplus/header_source_icon.png"; // NOI18N
private static CppSwitchAction instance;
private static final RequestProcessor RP = new RequestProcessor(CppSwitchAction.class.getName(), 1);

public static synchronized CppSwitchAction getInstance() {
if (instance == null) {
instance = new CppSwitchAction();
}
return instance;
}

private CppSwitchAction() {
super(ACTION_NAME);
putValue("noIconInMenu", Boolean.TRUE); //NOI18N
putValue(BaseAction.ICON_RESOURCE_PROPERTY, ICON);
putValue(SHORT_DESCRIPTION, getDefaultShortDescription());
}

@Override
public void actionPerformed(ActionEvent evt, JTextComponent txt) {
DataObject activatedDataObject = getActivatedDataObject();
if (activatedDataObject != null) {
FileObject res = findToggleFile(activatedDataObject);
boolean isToggled = false;
if (res != null) {
doToggle(res);
isToggled = true;
}
if (!isToggled) {
String status;
switch (getTargetNodeKind(activatedDataObject)) {
case HEADER:
status = getMessage("cpp-switch-source-not-found"); //NOI18N
break;
case SOURCE:
status = getMessage("cpp-switch-header-not-found"); //NOI18N
break;
default:
status = getMessage("cpp-switch-file-not-found");
}
StatusDisplayer.getDefault().setStatusText(status); // NOI18N
}
}
}

public @Override String getPopupMenuText(JTextComponent target) {
String trimmedNameKey = "goto-cpp-switch-file"; //NOI18N
switch (getTargetNodeKind(getActivatedDataObject())) {
case HEADER:
trimmedNameKey = "goto-cpp-header-file"; //NOI18N
break;
case SOURCE:
trimmedNameKey = "goto-cpp-source-file"; //NOI18N
break;
}
return getMessage(trimmedNameKey);
}

protected @Override Object getDefaultShortDescription() {
return getMessage("cpp-switch-header-source"); //NOI18N
}

@Override
protected boolean asynchonous() {
return true;
}

// File search functionality

private enum NodeKind {

HEADER, SOURCE, UNKNOWN
}

private DataObject getActivatedDataObject(){
DataObject dob = null;
Node[] activatedNodes = TopComponent.getRegistry().getActivatedNodes();
if (activatedNodes != null && activatedNodes.length == 1) {
dob = activatedNodes[0].getLookup().lookup(DataObject.class);
}
if (dob == null) {
TopComponent activated = TopComponent.getRegistry().getActivated();
if (activated != null && WindowManager.getDefault().isOpenedEditorTopComponent(activated)) {
dob = activated.getLookup().lookup(DataObject.class);
}
}
return dob;
}

private static NodeKind getTargetNodeKind(DataObject dobj) {
if (dobj != null) {
FileObject fo = dobj.getPrimaryFile();
String mime = (fo == null) ? "" : fo.getMIMEType();
if (MIMENames.HEADER_MIME_TYPE.equals(mime)) {
return NodeKind.SOURCE;
} else if (MIMENames.isCppOrC(mime)) {
return NodeKind.HEADER;
}
}
return NodeKind.UNKNOWN;
}

private static void doToggle(final DataObject toggled) {
// check if the data object has possibility to be opened in editor
final OpenCookie oc = toggled.getLookup().lookup(OpenCookie.class);
if (oc != null) {
// remember current caret position
JTextComponent textComponent = EditorRegistry.lastFocusedComponent();
JumpList.checkAddEntry(textComponent);
// try to open ASAP, but better not in EQ
RP.post(new Runnable() {

@Override
public void run() {
// open component
oc.open();
}
}, 0, Thread.MAX_PRIORITY);
}
}

private static void doToggle(FileObject fo) {
assert (fo != null);
try {
// find a data object for the input file object
DataObject toggled = DataObject.find(fo);
if (toggled != null) {
doToggle(toggled);
}
} catch (DataObjectNotFoundException ex) {
// may be error message?
}
}

private static FileObject findToggleFile(DataObject dob) {
FileObject res = null;
// check whether current file is C++ Source file
FileObject fo = dob.getPrimaryFile();
if (fo != null) {
String mimeType = FileUtil.getMIMEType(fo, MIMENames.HEADER_MIME_TYPE, MIMENames.CPLUSPLUS_MIME_TYPE, MIMENames.C_MIME_TYPE);
if (MIMENames.isCppOrC(mimeType)) {
// it was Source file, find Header
res = findBrother(dob, MIMEExtensions.get(MIMENames.HEADER_MIME_TYPE).getValues());
} else if (MIMENames.HEADER_MIME_TYPE.equals(mimeType)) {
// check whether current file is Header file
// try to find C++ Source file
res = findBrother(dob, MIMEExtensions.get(MIMENames.CPLUSPLUS_MIME_TYPE).getValues());
if (res == null) {
// try to find C Source file
res = findBrother(dob, MIMEExtensions.get(MIMENames.C_MIME_TYPE).getValues());
}
}
}
return res;
}

private static FileObject findBrother(DataObject dob, Collection<String> extensions) {
assert (dob != null);
assert (dob.getPrimaryFile() != null);
if (!extensions.isEmpty()) {
// get a file object associated with the data object
FileObject fo = dob.getPrimaryFile();
FileObject[] childs = fo.getParent().getChildren();

// try to find a file with the same name and one of passed extensions
for (String ext : extensions) {
// use FileUtilities to find brother of the file object
// FileObject res = FileUtil.findBrother(fo, ext[i]);

// IZ117750. Netbeans don't recognize MAC FS as case-insensitive
// so FileObject.getFileObject(name, extension) can create
// separate FileObjects for name.h and name.H although they are names
// of the same file. So FileUtil.findBrother can't be used for now.

String ne = fo.getName() + '.' + ext;
for (int j = 0; j < childs.length; j++) {
FileObject fileObject = childs[j];
if ( CndFileUtils.areFilenamesEqual( fileObject.getNameExt(), ne )) {
return fileObject;
}
}
}
}
return null;
}

// Utility

private static String getMessage(String key) {
return NbBundle.getMessage(CppSwitchAction.class, key);
}
}
51 changes: 51 additions & 0 deletions cnd/cnd.editor/src/org/netbeans/modules/cnd/editor/layer.xml
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,13 @@
<folder name="goto">
<attr name="position" intvalue="100"/>
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.cnd.editor.resources.Bundle"/>
<file name="cpp-switch-header-source">
<attr name="position" intvalue="200"/>
</file>
<file name="SeparatorBeforeInspect.instance">
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
<attr name="position" intvalue="1000"/>
</file>
</folder>
<file name="SeparatorBeforeFormat.instance">
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
Expand Down Expand Up @@ -292,13 +299,23 @@
<file name="uncomment">
<attr name="position" intvalue="19300"/>
</file>
<file name="cpp-switch-header-source">
<attr name="position" intvalue="19400"/>
</file>
</folder>
</folder>
<folder name="BracesMatchers">
<file name="org-netbeans-modules-cnd-editor-cplusplus-CppBracesMatcher.instance">
<attr name="position" intvalue="0"/>
</file>
</folder>
<folder name="Actions">
<file name="org-netbeans-modules-cnd-editor-cplusplus-CppSwitchAction.instance">
<attr name="instanceOf" stringvalue="javax.swing.Action"/>
<attr name="instanceClass" stringvalue="org.netbeans.modules.cnd.editor.cplusplus.CppSwitchAction"/>
<attr name="instanceCreate" methodvalue="org.netbeans.modules.cnd.editor.cplusplus.CppSwitchAction.getInstance"/>
</file>
</folder>
<file name="Reformatter.instance">
<attr name="instanceOf" stringvalue="org.netbeans.modules.editor.indent.spi.ReformatTask$Factory"/>
<attr name="instanceClass" stringvalue="org.netbeans.modules.cnd.editor.reformat.Reformatter$Factory"/>
Expand Down Expand Up @@ -396,6 +413,13 @@
<folder name="goto">
<attr name="position" intvalue="100"/>
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.cnd.editor.resources.Bundle"/>
<file name="cpp-switch-header-source">
<attr name="position" intvalue="200"/>
</file>
<file name="SeparatorBeforeInspect.instance">
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
<attr name="position" intvalue="1000"/>
</file>
</folder>
<file name="SeparatorBeforeFormat.instance">
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
Expand Down Expand Up @@ -428,13 +452,23 @@
<file name="uncomment">
<attr name="position" intvalue="19300"/>
</file>
<file name="cpp-switch-header-source">
<attr name="position" intvalue="19400"/>
</file>
</folder>
</folder>
<folder name="BracesMatchers">
<file name="org-netbeans-modules-cnd-editor-cplusplus-CppBracesMatcher.instance">
<attr name="position" intvalue="0"/>
</file>
</folder>
<folder name="Actions">
<file name="org-netbeans-modules-cnd-editor-cplusplus-CppSwitchAction.instance">
<attr name="instanceOf" stringvalue="javax.swing.Action"/>
<attr name="instanceClass" stringvalue="org.netbeans.modules.cnd.editor.cplusplus.CppSwitchAction"/>
<attr name="instanceCreate" methodvalue="org.netbeans.modules.cnd.editor.cplusplus.CppSwitchAction.getInstance"/>
</file>
</folder>
<file name="Reformatter.instance">
<attr name="instanceOf" stringvalue="org.netbeans.modules.editor.indent.spi.ReformatTask$Factory"/>
<attr name="instanceClass" stringvalue="org.netbeans.modules.cnd.editor.reformat.Reformatter$Factory"/>
Expand Down Expand Up @@ -533,6 +567,13 @@
<folder name="goto">
<attr name="position" intvalue="100"/>
<attr name="SystemFileSystem.localizingBundle" stringvalue="org.netbeans.modules.cnd.editor.resources.Bundle"/>
<file name="cpp-switch-header-source">
<attr name="position" intvalue="200"/>
</file>
<file name="SeparatorBeforeInspect.instance">
<attr name="instanceClass" stringvalue="javax.swing.JSeparator"/>
<attr name="position" intvalue="1000"/>
</file>
</folder>

<file name="SeparatorBeforeFormat.instance">
Expand Down Expand Up @@ -566,13 +607,23 @@
<file name="uncomment">
<attr name="position" intvalue="19300"/>
</file>
<file name="cpp-switch-header-source">
<attr name="position" intvalue="19400"/>
</file>
</folder>
</folder>
<folder name="BracesMatchers">
<file name="org-netbeans-modules-cnd-editor-cplusplus-CppBracesMatcher.instance">
<attr name="position" intvalue="0"/>
</file>
</folder>
<folder name="Actions">
<file name="org-netbeans-modules-cnd-editor-cplusplus-CppSwitchAction.instance">
<attr name="instanceOf" stringvalue="javax.swing.Action"/>
<attr name="instanceClass" stringvalue="org.netbeans.modules.cnd.editor.cplusplus.CppSwitchAction"/>
<attr name="instanceCreate" methodvalue="org.netbeans.modules.cnd.editor.cplusplus.CppSwitchAction.getInstance"/>
</file>
</folder>
<file name="Reformatter.instance">
<attr name="instanceOf" stringvalue="org.netbeans.modules.editor.indent.spi.ReformatTask$Factory"/>
<attr name="instanceClass" stringvalue="org.netbeans.modules.cnd.editor.reformat.Reformatter$Factory"/>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
<bindings>
<bind actionName="complete-line" key="D-SEMICOLON"/>
<bind actionName="complete-line-newline" key="DS-SEMICOLON"/>
<bind actionName="cpp-switch-header-source" key="DS-A"/>
<!--
the next line is to prevent user from confusing.
otherwise goto-super-implementation which is disabled for
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 8272f00

Please sign in to comment.