forked from redhat-developer/intellij-quarkus
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Create a Quarkus Dev Explorer in the IDE
Fixes redhat-developer#1175 Signed-off-by: azerr <[email protected]>
- Loading branch information
1 parent
9c95979
commit fd5554a
Showing
14 changed files
with
570 additions
and
4 deletions.
There are no files selected for viewing
45 changes: 45 additions & 0 deletions
45
src/main/java/com/redhat/devtools/intellij/quarkus/QuarkusBundle.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Red Hat Inc. and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
* which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package com.redhat.devtools.intellij.quarkus; | ||
|
||
import com.intellij.DynamicBundle; | ||
import org.jetbrains.annotations.Nls; | ||
import org.jetbrains.annotations.NonNls; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.PropertyKey; | ||
|
||
import java.util.function.Supplier; | ||
|
||
/** | ||
* Quarkus messages bundle. | ||
*/ | ||
public final class QuarkusBundle extends DynamicBundle { | ||
|
||
@NonNls public static final String BUNDLE = "messages.QuarkusBundle"; | ||
private static final QuarkusBundle INSTANCE = new QuarkusBundle(); | ||
|
||
private QuarkusBundle() { | ||
super(BUNDLE); | ||
} | ||
|
||
@NotNull | ||
public static @Nls String message(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) { | ||
return INSTANCE.getMessage(key, params); | ||
} | ||
|
||
@NotNull | ||
public static Supplier<@Nls String> messagePointer(@NotNull @PropertyKey(resourceBundle = BUNDLE) String key, Object @NotNull ... params) { | ||
return INSTANCE.getLazyMessage(key, params); | ||
} | ||
} |
35 changes: 35 additions & 0 deletions
35
src/main/java/com/redhat/devtools/intellij/quarkus/explorer/QuarkusActionNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,35 @@ | ||
package com.redhat.devtools.intellij.quarkus.explorer; | ||
|
||
import com.intellij.icons.AllIcons; | ||
import com.intellij.openapi.module.Module; | ||
|
||
import javax.swing.*; | ||
import javax.swing.tree.DefaultMutableTreeNode; | ||
|
||
public class QuarkusActionNode extends DefaultMutableTreeNode { | ||
|
||
private final String name; | ||
|
||
private final Module module; | ||
|
||
public QuarkusActionNode(String name, Module module) { | ||
this.name = name; | ||
this.module = module; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public Module getModule() { | ||
return module; | ||
} | ||
|
||
public String getDisplayName() { | ||
return name; | ||
} | ||
|
||
public Icon getIcon() { | ||
return AllIcons.Actions.InlayGear; | ||
} | ||
} |
126 changes: 126 additions & 0 deletions
126
src/main/java/com/redhat/devtools/intellij/quarkus/explorer/QuarkusExplorer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,126 @@ | ||
package com.redhat.devtools.intellij.quarkus.explorer; | ||
|
||
import com.intellij.ide.DataManager; | ||
import com.intellij.openapi.Disposable; | ||
import com.intellij.openapi.actionSystem.*; | ||
import com.intellij.openapi.application.ReadAction; | ||
import com.intellij.openapi.module.Module; | ||
import com.intellij.openapi.module.ModuleManager; | ||
import com.intellij.openapi.project.DumbService; | ||
import com.intellij.openapi.project.Project; | ||
import com.intellij.openapi.ui.SimpleToolWindowPanel; | ||
import com.intellij.ui.AnimatedIcon; | ||
import com.intellij.ui.DoubleClickListener; | ||
import com.intellij.ui.treeStructure.Tree; | ||
import com.intellij.util.concurrency.AppExecutorUtil; | ||
import com.redhat.devtools.intellij.lsp4ij.console.explorer.LanguageServerTreeRenderer; | ||
import com.redhat.devtools.intellij.quarkus.explorer.actions.QuarkusDevStartAction; | ||
import com.redhat.microprofile.psi.quarkus.PsiQuarkusUtils; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import javax.swing.tree.DefaultMutableTreeNode; | ||
import javax.swing.tree.DefaultTreeModel; | ||
import javax.swing.tree.TreePath; | ||
import java.awt.event.KeyAdapter; | ||
import java.awt.event.KeyEvent; | ||
import java.awt.event.MouseEvent; | ||
|
||
public class QuarkusExplorer extends SimpleToolWindowPanel implements Disposable { | ||
|
||
private final Tree tree; | ||
private final Project project; | ||
|
||
public QuarkusExplorer(@NotNull Project project) { | ||
super(true, true); | ||
this.project = project; | ||
tree = buildTree(); | ||
this.setContent(tree); | ||
load(); | ||
} | ||
|
||
/** | ||
* Builds the Language server tree | ||
* | ||
* @return Tree object of all language servers | ||
*/ | ||
private Tree buildTree() { | ||
|
||
DefaultMutableTreeNode top = new DefaultMutableTreeNode("Quarkus projects"); | ||
|
||
Tree tree = new Tree(top); | ||
tree.setRootVisible(false); | ||
tree.setCellRenderer(new QuarkusTreeRenderer()); | ||
|
||
tree.putClientProperty(AnimatedIcon.ANIMATION_IN_RENDERER_ALLOWED, true); | ||
|
||
((DefaultTreeModel) tree.getModel()).reload(top); | ||
|
||
|
||
var doubleClickListener = new DoubleClickListener() { | ||
@Override | ||
protected boolean onDoubleClick(@NotNull MouseEvent event) { | ||
executeAction(tree); | ||
return false; | ||
} | ||
}; | ||
doubleClickListener.installOn(tree); | ||
|
||
tree.addKeyListener(new KeyAdapter() { | ||
@Override | ||
public void keyPressed(KeyEvent e) { | ||
if (e.getKeyCode() == KeyEvent.VK_ENTER) { | ||
executeAction(tree); | ||
} | ||
} | ||
}); | ||
|
||
return tree; | ||
} | ||
|
||
private void load() { | ||
var action = ReadAction.nonBlocking(() -> { | ||
DefaultMutableTreeNode root = (DefaultMutableTreeNode) ((DefaultTreeModel) tree.getModel()).getRoot(); | ||
Module[] modules = ModuleManager.getInstance(project).getModules(); | ||
for (Module javaProject : modules) { | ||
if (PsiQuarkusUtils.isQuarkusProject(javaProject)) { | ||
QuarkusProjectNode projectNode = new QuarkusProjectNode(javaProject); | ||
root.add(projectNode); | ||
// Fill Quarkus actions | ||
projectNode.add(new QuarkusActionNode("Start", javaProject)); | ||
} | ||
} | ||
((DefaultTreeModel) tree.getModel()).reload(root); | ||
}); | ||
var executeInSmartMode = DumbService.getInstance(project).isDumb(); | ||
if (executeInSmartMode) { | ||
action = action.inSmartMode(project); | ||
} | ||
action | ||
.submit(AppExecutorUtil.getAppExecutorService()); | ||
} | ||
|
||
private static void executeAction(Tree tree) { | ||
final TreePath path = tree.getSelectionPath(); | ||
Object node = path.getLastPathComponent(); | ||
if (node instanceof QuarkusActionNode) { | ||
ActionManager am = ActionManager.getInstance(); | ||
String actionNodeName = ((QuarkusActionNode) node).getName(); | ||
|
||
String actionId = QuarkusDevStartAction.ACTION_ID; | ||
|
||
AnAction action = am.getAction(actionId); | ||
if (action != null) { | ||
action.actionPerformed(new AnActionEvent(null, | ||
DataManager.getInstance().getDataContext(tree), | ||
ActionPlaces.UNKNOWN, new Presentation(), | ||
am, 0)); | ||
} | ||
|
||
} | ||
} | ||
|
||
@Override | ||
public void dispose() { | ||
|
||
} | ||
} |
25 changes: 25 additions & 0 deletions
25
src/main/java/com/redhat/devtools/intellij/quarkus/explorer/QuarkusProjectNode.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,25 @@ | ||
package com.redhat.devtools.intellij.quarkus.explorer; | ||
|
||
import com.intellij.openapi.module.Module; | ||
import com.redhat.devtools.intellij.quarkus.lang.QuarkusIcons; | ||
|
||
import javax.swing.*; | ||
import javax.swing.tree.DefaultMutableTreeNode; | ||
|
||
public class QuarkusProjectNode extends DefaultMutableTreeNode { | ||
|
||
private final Module module; | ||
|
||
public QuarkusProjectNode(Module module) { | ||
this.module = module; | ||
} | ||
|
||
public String getDisplayName() { | ||
return module.getName(); | ||
} | ||
|
||
public Icon getIcon() { | ||
return QuarkusIcons.Quarkus; | ||
} | ||
|
||
} |
24 changes: 24 additions & 0 deletions
24
src/main/java/com/redhat/devtools/intellij/quarkus/explorer/QuarkusToolWindowFactory.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,24 @@ | ||
package com.redhat.devtools.intellij.quarkus.explorer; | ||
|
||
import com.intellij.openapi.project.Project; | ||
import com.intellij.openapi.wm.ToolWindow; | ||
import com.intellij.openapi.wm.ToolWindowFactory; | ||
import com.intellij.ui.content.Content; | ||
import com.intellij.ui.content.ContentManager; | ||
import com.redhat.devtools.intellij.lsp4ij.LanguageServerBundle; | ||
import com.redhat.devtools.intellij.quarkus.QuarkusBundle; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
public class QuarkusToolWindowFactory implements ToolWindowFactory { | ||
|
||
@Override | ||
public void createToolWindowContent(@NotNull Project project, @NotNull ToolWindow toolWindow) { | ||
QuarkusExplorer explorer = new QuarkusExplorer(project); | ||
ContentManager contentManager = toolWindow.getContentManager(); | ||
Content content = contentManager.getFactory().createContent(explorer, | ||
QuarkusBundle.message("quarkus.tool.window.display.name"), false); | ||
content.setDisposer(explorer); | ||
contentManager.addContent(content); | ||
|
||
} | ||
} |
133 changes: 133 additions & 0 deletions
133
src/main/java/com/redhat/devtools/intellij/quarkus/explorer/QuarkusTreeRenderer.java
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,133 @@ | ||
/******************************************************************************* | ||
* Copyright (c) 2023 Red Hat Inc. and others. | ||
* | ||
* This program and the accompanying materials are made available under the | ||
* terms of the Eclipse Public License v. 2.0 which is available at | ||
* http://www.eclipse.org/legal/epl-2.0, or the Apache License, Version 2.0 | ||
* which is available at https://www.apache.org/licenses/LICENSE-2.0. | ||
* | ||
* SPDX-License-Identifier: EPL-2.0 OR Apache-2.0 | ||
* | ||
* Contributors: | ||
* Red Hat Inc. - initial API and implementation | ||
*******************************************************************************/ | ||
package com.redhat.devtools.intellij.quarkus.explorer; | ||
|
||
import com.intellij.ide.ui.UISettings; | ||
import com.intellij.ui.ColoredTreeCellRenderer; | ||
import com.intellij.ui.RelativeFont; | ||
import com.intellij.ui.SimpleTextAttributes; | ||
import com.intellij.util.ui.UIUtil; | ||
import com.redhat.devtools.intellij.lsp4ij.ServerStatus; | ||
import com.redhat.devtools.intellij.lsp4ij.console.explorer.LanguageServerProcessTreeNode; | ||
import com.redhat.devtools.intellij.lsp4ij.console.explorer.LanguageServerTreeNode; | ||
import org.jetbrains.annotations.NonNls; | ||
import org.jetbrains.annotations.NotNull; | ||
|
||
import javax.swing.*; | ||
import java.awt.*; | ||
|
||
/** | ||
* Quarkus tree nodes renderer. | ||
* <p> | ||
* Some piece of code has been copied/pasted from https://github.com/JetBrains/intellij-community/blob/master/platform/smRunner/src/com/intellij/execution/testframework/sm/runner/ui/TestTreeRenderer.java and adapted for Language Server case. | ||
*/ | ||
public class QuarkusTreeRenderer extends ColoredTreeCellRenderer { | ||
|
||
@NonNls | ||
private static final String SPACE_STRING = " "; | ||
private String myDurationText; | ||
private Color myDurationColor; | ||
private int myDurationWidth; | ||
private int myDurationOffset; | ||
|
||
@Override | ||
public void customizeCellRenderer(@NotNull final JTree tree, | ||
final Object value, | ||
final boolean selected, | ||
final boolean expanded, | ||
final boolean leaf, | ||
final int row, | ||
final boolean hasFocus) { | ||
myDurationText = null; | ||
myDurationColor = null; | ||
myDurationWidth = 0; | ||
myDurationOffset = 0; | ||
|
||
if (value instanceof QuarkusProjectNode) { | ||
// Render of Quarkus project | ||
QuarkusProjectNode projectNode = (QuarkusProjectNode) value; | ||
setIcon(projectNode.getIcon()); | ||
append(projectNode.getDisplayName()); | ||
return; | ||
} | ||
|
||
if (value instanceof QuarkusActionNode) { | ||
// Render of Quarkus action | ||
QuarkusActionNode actionNode = (QuarkusActionNode) value; | ||
setIcon(actionNode.getIcon()); | ||
append(actionNode.getDisplayName()); | ||
return; | ||
} | ||
|
||
/*if (value instanceof LanguageServerProcessTreeNode) { | ||
// Render of language server process | ||
LanguageServerProcessTreeNode languageProcessTreeNode = (LanguageServerProcessTreeNode) value; | ||
setIcon(languageProcessTreeNode.getIcon()); | ||
append(languageProcessTreeNode.getDisplayName()); | ||
if (languageProcessTreeNode.getServerStatus() == ServerStatus.starting | ||
|| languageProcessTreeNode.getServerStatus() == ServerStatus.stopping) { | ||
// Display elapsed time when language server is starting/stopping | ||
myDurationText = languageProcessTreeNode.getElapsedTime(); | ||
final var durationText = myDurationText; | ||
if (durationText != null) { | ||
FontMetrics metrics = getFontMetrics(RelativeFont.SMALL.derive(getFont())); | ||
myDurationWidth = metrics.stringWidth(durationText); | ||
myDurationOffset = metrics.getHeight() / 2; // an empty area before and after the text | ||
myDurationColor = selected ? UIUtil.getTreeSelectionForeground(hasFocus) : SimpleTextAttributes.GRAYED_ATTRIBUTES.getFgColor(); | ||
} | ||
} | ||
return; | ||
}*/ | ||
//strange node | ||
final String text = value.toString(); | ||
//no icon | ||
append(text != null ? text : SPACE_STRING, SimpleTextAttributes.GRAYED_ATTRIBUTES); | ||
} | ||
|
||
@NotNull | ||
@Override | ||
public Dimension getPreferredSize() { | ||
final Dimension preferredSize = super.getPreferredSize(); | ||
if (myDurationWidth > 0) preferredSize.width += myDurationWidth + myDurationOffset; | ||
return preferredSize; | ||
} | ||
|
||
@Override | ||
protected void paintComponent(Graphics g) { | ||
UISettings.setupAntialiasing(g); | ||
Shape clip = null; | ||
int width = getWidth(); | ||
int height = getHeight(); | ||
if (isOpaque()) { | ||
// paint background for expanded row | ||
g.setColor(getBackground()); | ||
g.fillRect(0, 0, width, height); | ||
} | ||
if (myDurationWidth > 0) { | ||
width -= myDurationWidth + myDurationOffset; | ||
if (width > 0 && height > 0) { | ||
g.setColor(myDurationColor); | ||
g.setFont(RelativeFont.SMALL.derive(getFont())); | ||
g.drawString(myDurationText, width + myDurationOffset / 2, getTextBaseLine(g.getFontMetrics(), height)); | ||
clip = g.getClip(); | ||
g.clipRect(0, 0, width, height); | ||
} | ||
} | ||
super.paintComponent(g); | ||
// restore clip area if needed | ||
if (clip != null) g.setClip(clip); | ||
} | ||
} | ||
|
Oops, something went wrong.