-
Notifications
You must be signed in to change notification settings - Fork 51
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 #1175 Signed-off-by: azerr <[email protected]>
- Loading branch information
1 parent
9c95979
commit 2ea8d22
Showing
16 changed files
with
733 additions
and
6 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); | ||
} | ||
} |
42 changes: 42 additions & 0 deletions
42
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,42 @@ | ||
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; | ||
import javax.swing.tree.DefaultTreeModel; | ||
|
||
public class QuarkusActionNode extends DefaultMutableTreeNode { | ||
|
||
private final String name; | ||
|
||
private final Module module; | ||
|
||
private final DefaultTreeModel treeModel; | ||
public QuarkusActionNode(String name, Module module, DefaultTreeModel treeModel) { | ||
this.name = name; | ||
this.module = module; | ||
this.treeModel = treeModel; | ||
} | ||
|
||
public String getName() { | ||
return name; | ||
} | ||
|
||
public Module getModule() { | ||
return module; | ||
} | ||
|
||
public String getDisplayName() { | ||
return name; | ||
} | ||
|
||
public Icon getIcon() { | ||
return AllIcons.Actions.InlayGear; | ||
} | ||
|
||
public void refreshNode() { | ||
treeModel.nodeChanged(this); | ||
} | ||
} |
218 changes: 218 additions & 0 deletions
218
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,218 @@ | ||
package com.redhat.devtools.intellij.quarkus.explorer; | ||
|
||
import com.intellij.execution.ExecutionListener; | ||
import com.intellij.execution.ExecutionManager; | ||
import com.intellij.execution.RunManagerListener; | ||
import com.intellij.execution.RunnerAndConfigurationSettings; | ||
import com.intellij.execution.process.ProcessHandler; | ||
import com.intellij.execution.runners.ExecutionEnvironment; | ||
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.intellij.util.messages.MessageBusConnection; | ||
import com.redhat.devtools.intellij.quarkus.explorer.actions.QuarkusDevStartAction; | ||
import com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration; | ||
import com.redhat.microprofile.psi.quarkus.PsiQuarkusUtils; | ||
import org.jetbrains.annotations.NotNull; | ||
import org.jetbrains.annotations.Nullable; | ||
|
||
import javax.swing.tree.DefaultMutableTreeNode; | ||
import javax.swing.tree.DefaultTreeModel; | ||
import javax.swing.tree.TreeNode; | ||
import javax.swing.tree.TreePath; | ||
import java.awt.event.KeyAdapter; | ||
import java.awt.event.KeyEvent; | ||
import java.awt.event.MouseEvent; | ||
import java.util.Enumeration; | ||
|
||
import static com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration.QUARKUS_CONFIGURATION; | ||
|
||
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); | ||
} | ||
} | ||
}); | ||
|
||
MessageBusConnection connection = project.getMessageBus().connect(project); | ||
connection.subscribe(RunManagerListener.TOPIC, new RunManagerListener() { | ||
@Override | ||
public void runConfigurationSelected(@Nullable RunnerAndConfigurationSettings settings) { | ||
// Do nothing | ||
} | ||
|
||
@Override | ||
public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) { | ||
// TODO: refresh tree | ||
} | ||
}); | ||
connection.subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionListener() { | ||
|
||
@Override | ||
public void processStarting(@NotNull String executorId, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler handler) { | ||
QuarkusRunApplicationNode application = findQuarkusApplication(env); | ||
if (application != null) { | ||
application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.starting); | ||
} | ||
} | ||
|
||
@Override | ||
public void processNotStarted(@NotNull String executorId, @NotNull ExecutionEnvironment env) { | ||
QuarkusRunApplicationNode application = findQuarkusApplication(env); | ||
if (application != null) { | ||
application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.stopped); | ||
} | ||
} | ||
|
||
@Override | ||
public void processStarted(@NotNull String executorId, @NotNull ExecutionEnvironment env, final @NotNull ProcessHandler handler) { | ||
QuarkusRunApplicationNode application = findQuarkusApplication(env); | ||
if (application != null) { | ||
application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.started); | ||
} | ||
} | ||
|
||
@Override | ||
public void processTerminating(@NotNull String executorId, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler handler) { | ||
QuarkusRunApplicationNode application = findQuarkusApplication(env); | ||
if (application != null) { | ||
application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.stopping); | ||
} | ||
} | ||
|
||
@Override | ||
public void processTerminated(@NotNull String executorId, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler handler, int exitCode) { | ||
QuarkusRunApplicationNode application = findQuarkusApplication(env); | ||
if (application != null) { | ||
application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.stopped); | ||
} | ||
} | ||
|
||
private @Nullable QuarkusRunApplicationNode findQuarkusApplication(@NotNull ExecutionEnvironment env) { | ||
QuarkusRunConfiguration runConfiguration = env.getDataContext() != null ? (QuarkusRunConfiguration) env.getDataContext().getData(QUARKUS_CONFIGURATION) : null; | ||
if (runConfiguration == null) { | ||
return null; | ||
} | ||
|
||
Module module = runConfiguration.getModule(); | ||
DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot(); | ||
Enumeration<TreeNode> children = root.children(); | ||
while (children.hasMoreElements()) { | ||
TreeNode node = children.nextElement(); | ||
if (node instanceof QuarkusProjectNode && module.equals(((QuarkusProjectNode) node).getModule())) { | ||
QuarkusProjectNode project = (QuarkusProjectNode) node; | ||
Enumeration<TreeNode> children2 = project.children(); | ||
while (children2.hasMoreElements()) { | ||
TreeNode node2 = children2.nextElement(); | ||
if (node2 instanceof QuarkusRunApplicationNode && runConfiguration.equals(((QuarkusRunApplicationNode) node2).getConfiguration())) { | ||
return (QuarkusRunApplicationNode) node2; | ||
} | ||
} | ||
break; | ||
} | ||
} | ||
return null; | ||
} | ||
}); | ||
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 QuarkusRunApplicationNode(javaProject, (DefaultTreeModel) tree.getModel())); | ||
} | ||
} | ||
((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() { | ||
|
||
} | ||
} |
28 changes: 28 additions & 0 deletions
28
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,28 @@ | ||
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; | ||
} | ||
|
||
public Module getModule() { | ||
return module; | ||
} | ||
} |
45 changes: 45 additions & 0 deletions
45
src/main/java/com/redhat/devtools/intellij/quarkus/explorer/QuarkusRunApplicationNode.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 @@ | ||
package com.redhat.devtools.intellij.quarkus.explorer; | ||
|
||
import com.intellij.execution.configurations.RunConfiguration; | ||
import com.intellij.openapi.module.Module; | ||
import com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration; | ||
|
||
import javax.swing.tree.DefaultTreeModel; | ||
|
||
public class QuarkusRunApplicationNode extends QuarkusActionNode{ | ||
|
||
private RunConfiguration configuration; | ||
|
||
public void setConfiguration(RunConfiguration configuration) { | ||
this.configuration = configuration; | ||
} | ||
|
||
public RunConfiguration getConfiguration() { | ||
return configuration; | ||
} | ||
|
||
public static enum QuarkusApplicationStatus { | ||
none, | ||
starting, | ||
started, | ||
stopping, | ||
stopped; | ||
} | ||
|
||
private QuarkusApplicationStatus applicationStatus; | ||
|
||
public QuarkusRunApplicationNode(Module module, DefaultTreeModel treeModel) { | ||
super("Run...", module, treeModel); | ||
this.applicationStatus = QuarkusApplicationStatus.none; | ||
} | ||
|
||
public void setApplicationStatus(QuarkusApplicationStatus applicationStatus) { | ||
this.applicationStatus = applicationStatus; | ||
refreshNode(); | ||
} | ||
|
||
@Override | ||
public String getDisplayName() { | ||
return super.getDisplayName() + " [" + applicationStatus + "]"; | ||
} | ||
} |
Oops, something went wrong.