How to display method text in an EditorTextField?

Answered

I'm having some trouble displaying the text of a Java method in a EditorTextField that is in a tool window. Below is the code I have now. I am expecting it to display the method body of the first method in the currently opened class in an EditorTextField in the tool window, but it just shows an empty EditorTextField instead. What could I be doing wrong?

public class EditorNodeTest implements ToolWindowFactory {

@Override
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
JFXPanel fxPanel = new JFXPanel();

DumbService.getInstance(project).smartInvokeLater(() -> Platform.runLater(() -> {
// Create the Java editor node.
PsiClass currentClass = getCurrentClass(project);
PsiMethod method = currentClass.getMethods()[0];
JavaCodeFragmentFactory javaFactory = JavaCodeFragmentFactory.getInstance(project);
PsiExpressionCodeFragment code = javaFactory.createExpressionCodeFragment(method.getBody().getText(), method, null, true);
Document document = ApplicationManager.getApplication().runReadAction((Computable<Document>) () -> PsiDocumentManager.getInstance(project).getDocument(code));
EditorTextField myInput = new EditorTextField(document, project, JavaFileType.INSTANCE);
SwingNode editorNode = new SwingNode();
editorNode.setContent(myInput.getComponent());

// Add the editor node to the scene.
VBox root = new VBox();
root.getChildren().add(editorNode);
Scene scene = new Scene(root);
fxPanel.setScene(scene);
}));

JComponent component = toolWindow.getComponent();
component.getParent().add(fxPanel);
}

protected static PsiClass getCurrentClass(Project p) {
// Get the currently selected file.
FileEditorManager manager = FileEditorManager.getInstance(p);
VirtualFile[] files = manager.getSelectedFiles();
VirtualFile currentFile = files[0];

// Get the PsiClass for the currently selected file.
final PsiClass[] curClass = new PsiClass[1];
ApplicationManager.getApplication().runReadAction(() -> {
PsiFile psiFile = PsiManager.getInstance(p).findFile(currentFile);
PsiJavaFile psiJavaFile = (PsiJavaFile) psiFile;
curClass[0] = psiJavaFile.getClasses()[0];
});

return curClass[0];
}
}

 

 

8 comments
Comment actions Permalink

First of all - is it necessary for you to use JFXPanel and so on?

I have simplified it to use just JPanel and EditorTextField was displayed correctly in the ToolWindow. However, the component that you have created is just a single line, so it displays me the first line of the content:

 

0
Comment actions Permalink

Yes, I do want to use JavaFX.

I was able to get it to show one line like in that screenshot with JavaFX by just adding the EditorTextField component to a JPanel before adding it to the SwingNode. However I want it to show all lines of the method body.

Do you know if there is a component that is like the EditorTextField but supports multiple lines? I know about the FileEditor component, but that seems to only work on entire files. I want to just show one method.

0
Comment actions Permalink

You can create an Editor using the following method:

EditorFactory.getInstance().createEditor(...)

It doesn't require the file to be present - just a document, which you can create also with EditorFactory passing the content string.

0
Comment actions Permalink

Thanks, I was able to get it to show the entire method body even without needing a JPanel, although for some reason I have to highlight the top of the tool window to show the method text in the editor. However I can't figure out how to make the editor actually editable. I created the Editor like so:

Editor editor = factory.createEditor(document, project, method.getContainingFile().getVirtualFile(), false);

 

but it still doesn't let me edit it. Here is the code I have so far for the createToolWindowContent method, and a screenshot. How can I make the Editor editable?

 

@Override
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) {
JFXPanel fxPanel = new JFXPanel();

DumbService.getInstance(project).smartInvokeLater(() -> Platform.runLater(() -> {
// Create the document to hold the method code.
PsiClass currentClass = getCurrentClass(project);
PsiMethod method = currentClass.getMethods()[0];
JavaCodeFragmentFactory javaFactory = JavaCodeFragmentFactory.getInstance(project);
PsiExpressionCodeFragment code = javaFactory.createExpressionCodeFragment(method.getBody().getText(), method, null, true);
Document document = ApplicationManager.getApplication().runReadAction((Computable<Document>) () -> PsiDocumentManager.getInstance(project).getDocument(code));

// Create the node containing the editor.
EditorFactory factory = EditorFactory.getInstance();
SwingNode editorNode = new SwingNode();
ApplicationManager.getApplication().invokeLater(() -> {
Editor editor = factory.createEditor(document, project, method.getContainingFile().getVirtualFile(), false);
editorNode.setContent(editor.getComponent());
});

// Add the editor node to the scene.
VBox root = new VBox();
root.getChildren().add(editorNode);
Scene scene = new Scene(root);
fxPanel.setScene(scene);
}));

0
Comment actions Permalink

By editing, you mean modifying the source file? Do I understand you correctly, that in ToolWindow you want to present just a part of the Java file and let the user edit it as in a regular editor?

0
Comment actions Permalink

Yes, that is what I want to do. I want it to look exactly like editing the Java source file in the regular editor with auto-complete, syntax highlighting, etc., except it's now in a tool window, and only shows the code for one method.

0
Comment actions Permalink

Syntax highlighting will report errors because your source provided to the editor will not be complete - missing surrounding class, no context, references to the other methods will not be resolved.

0
Comment actions Permalink

Shouldn't the references be resolved by providing the PsiMethod object when creating the PsiExpressionFragment object? Or is there another way to let the tool window editor know the context of the code it contains?

PsiExpressionCodeFragment code = javaFactory.createExpressionCodeFragment(method.getBody().getText(), method, null, true);

Also I got the editor to be editable by using a JPanel instead of JavaFX.

0

Please sign in to leave a comment.