|
| 1 | +package com.redhat.devtools.intellij.quarkus.explorer; |
| 2 | + |
| 3 | +import com.intellij.execution.ExecutionListener; |
| 4 | +import com.intellij.execution.ExecutionManager; |
| 5 | +import com.intellij.execution.RunManagerListener; |
| 6 | +import com.intellij.execution.RunnerAndConfigurationSettings; |
| 7 | +import com.intellij.execution.process.ProcessHandler; |
| 8 | +import com.intellij.execution.runners.ExecutionEnvironment; |
| 9 | +import com.intellij.ide.DataManager; |
| 10 | +import com.intellij.openapi.Disposable; |
| 11 | +import com.intellij.openapi.actionSystem.*; |
| 12 | +import com.intellij.openapi.application.ReadAction; |
| 13 | +import com.intellij.openapi.module.Module; |
| 14 | +import com.intellij.openapi.module.ModuleManager; |
| 15 | +import com.intellij.openapi.project.DumbService; |
| 16 | +import com.intellij.openapi.project.Project; |
| 17 | +import com.intellij.openapi.ui.SimpleToolWindowPanel; |
| 18 | +import com.intellij.ui.AnimatedIcon; |
| 19 | +import com.intellij.ui.DoubleClickListener; |
| 20 | +import com.intellij.ui.treeStructure.Tree; |
| 21 | +import com.intellij.util.concurrency.AppExecutorUtil; |
| 22 | +import com.intellij.util.messages.MessageBusConnection; |
| 23 | +import com.redhat.devtools.intellij.quarkus.explorer.actions.QuarkusDevStartAction; |
| 24 | +import com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration; |
| 25 | +import com.redhat.microprofile.psi.quarkus.PsiQuarkusUtils; |
| 26 | +import org.jetbrains.annotations.NotNull; |
| 27 | +import org.jetbrains.annotations.Nullable; |
| 28 | + |
| 29 | +import javax.swing.tree.DefaultMutableTreeNode; |
| 30 | +import javax.swing.tree.DefaultTreeModel; |
| 31 | +import javax.swing.tree.TreeNode; |
| 32 | +import javax.swing.tree.TreePath; |
| 33 | +import java.awt.event.KeyAdapter; |
| 34 | +import java.awt.event.KeyEvent; |
| 35 | +import java.awt.event.MouseEvent; |
| 36 | +import java.util.Enumeration; |
| 37 | + |
| 38 | +import static com.redhat.devtools.intellij.quarkus.run.QuarkusRunConfiguration.QUARKUS_CONFIGURATION; |
| 39 | + |
| 40 | +public class QuarkusExplorer extends SimpleToolWindowPanel implements Disposable { |
| 41 | + |
| 42 | + private final Tree tree; |
| 43 | + private final Project project; |
| 44 | + |
| 45 | + public QuarkusExplorer(@NotNull Project project) { |
| 46 | + super(true, true); |
| 47 | + this.project = project; |
| 48 | + tree = buildTree(); |
| 49 | + this.setContent(tree); |
| 50 | + load(); |
| 51 | + } |
| 52 | + |
| 53 | + /** |
| 54 | + * Builds the Language server tree |
| 55 | + * |
| 56 | + * @return Tree object of all language servers |
| 57 | + */ |
| 58 | + private Tree buildTree() { |
| 59 | + |
| 60 | + DefaultMutableTreeNode top = new DefaultMutableTreeNode("Quarkus projects"); |
| 61 | + |
| 62 | + Tree tree = new Tree(top); |
| 63 | + tree.setRootVisible(false); |
| 64 | + tree.setCellRenderer(new QuarkusTreeRenderer()); |
| 65 | + |
| 66 | + tree.putClientProperty(AnimatedIcon.ANIMATION_IN_RENDERER_ALLOWED, true); |
| 67 | + |
| 68 | + ((DefaultTreeModel) tree.getModel()).reload(top); |
| 69 | + |
| 70 | + |
| 71 | + var doubleClickListener = new DoubleClickListener() { |
| 72 | + @Override |
| 73 | + protected boolean onDoubleClick(@NotNull MouseEvent event) { |
| 74 | + executeAction(tree); |
| 75 | + return false; |
| 76 | + } |
| 77 | + }; |
| 78 | + doubleClickListener.installOn(tree); |
| 79 | + |
| 80 | + tree.addKeyListener(new KeyAdapter() { |
| 81 | + @Override |
| 82 | + public void keyPressed(KeyEvent e) { |
| 83 | + if (e.getKeyCode() == KeyEvent.VK_ENTER) { |
| 84 | + executeAction(tree); |
| 85 | + } |
| 86 | + } |
| 87 | + }); |
| 88 | + |
| 89 | + MessageBusConnection connection = project.getMessageBus().connect(project); |
| 90 | + connection.subscribe(RunManagerListener.TOPIC, new RunManagerListener() { |
| 91 | + @Override |
| 92 | + public void runConfigurationSelected(@Nullable RunnerAndConfigurationSettings settings) { |
| 93 | + // Do nothing |
| 94 | + } |
| 95 | + |
| 96 | + @Override |
| 97 | + public void runConfigurationAdded(@NotNull RunnerAndConfigurationSettings settings) { |
| 98 | + // TODO: refresh tree |
| 99 | + } |
| 100 | + }); |
| 101 | + connection.subscribe(ExecutionManager.EXECUTION_TOPIC, new ExecutionListener() { |
| 102 | + |
| 103 | + @Override |
| 104 | + public void processNotStarted(@NotNull String executorId, @NotNull ExecutionEnvironment env) { |
| 105 | + QuarkusRunApplicationNode application = findQuarkusApplication(env); |
| 106 | + if (application != null) { |
| 107 | + application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.stopped); |
| 108 | + } |
| 109 | + } |
| 110 | + |
| 111 | + @Override |
| 112 | + public void processStarted(@NotNull String executorId, @NotNull ExecutionEnvironment env, final @NotNull ProcessHandler handler) { |
| 113 | + QuarkusRunApplicationNode application = findQuarkusApplication(env); |
| 114 | + if (application != null) { |
| 115 | + application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.starting); |
| 116 | + } |
| 117 | + } |
| 118 | + |
| 119 | + @Override |
| 120 | + public void processTerminating(@NotNull String executorId, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler handler) { |
| 121 | + QuarkusRunApplicationNode application = findQuarkusApplication(env); |
| 122 | + if (application != null) { |
| 123 | + application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.stopping); |
| 124 | + } |
| 125 | + } |
| 126 | + |
| 127 | + @Override |
| 128 | + public void processTerminated(@NotNull String executorId, @NotNull ExecutionEnvironment env, @NotNull ProcessHandler handler, int exitCode) { |
| 129 | + QuarkusRunApplicationNode application = findQuarkusApplication(env); |
| 130 | + if (application != null) { |
| 131 | + application.setApplicationStatus(QuarkusRunApplicationNode.QuarkusApplicationStatus.stopped); |
| 132 | + } |
| 133 | + } |
| 134 | + |
| 135 | + private @Nullable QuarkusRunApplicationNode findQuarkusApplication(@NotNull ExecutionEnvironment env) { |
| 136 | + QuarkusRunConfiguration runConfiguration = env.getDataContext() != null ? (QuarkusRunConfiguration) env.getDataContext().getData(QUARKUS_CONFIGURATION) : null; |
| 137 | + if (runConfiguration == null) { |
| 138 | + return null; |
| 139 | + } |
| 140 | + |
| 141 | + Module module = runConfiguration.getModule(); |
| 142 | + DefaultMutableTreeNode root = (DefaultMutableTreeNode) tree.getModel().getRoot(); |
| 143 | + Enumeration<TreeNode> children = root.children(); |
| 144 | + while (children.hasMoreElements()) { |
| 145 | + TreeNode node = children.nextElement(); |
| 146 | + if (node instanceof QuarkusProjectNode && module.equals(((QuarkusProjectNode) node).getModule())) { |
| 147 | + QuarkusProjectNode project = (QuarkusProjectNode) node; |
| 148 | + Enumeration<TreeNode> children2 = project.children(); |
| 149 | + while (children2.hasMoreElements()) { |
| 150 | + TreeNode node2 = children2.nextElement(); |
| 151 | + if (node2 instanceof QuarkusRunApplicationNode && runConfiguration.equals(((QuarkusRunApplicationNode) node2).getConfiguration())) { |
| 152 | + return (QuarkusRunApplicationNode) node2; |
| 153 | + } |
| 154 | + } |
| 155 | + break; |
| 156 | + } |
| 157 | + } |
| 158 | + return null; |
| 159 | + } |
| 160 | + }); |
| 161 | + return tree; |
| 162 | + } |
| 163 | + |
| 164 | + private void load() { |
| 165 | + var action = ReadAction.nonBlocking(() -> { |
| 166 | + DefaultMutableTreeNode root = (DefaultMutableTreeNode) ((DefaultTreeModel) tree.getModel()).getRoot(); |
| 167 | + Module[] modules = ModuleManager.getInstance(project).getModules(); |
| 168 | + for (Module javaProject : modules) { |
| 169 | + if (PsiQuarkusUtils.isQuarkusProject(javaProject)) { |
| 170 | + QuarkusProjectNode projectNode = new QuarkusProjectNode(javaProject, tree); |
| 171 | + root.add(projectNode); |
| 172 | + // Fill Quarkus actions |
| 173 | + projectNode.add(new QuarkusRunApplicationNode(projectNode)); |
| 174 | + } |
| 175 | + } |
| 176 | + ((DefaultTreeModel) tree.getModel()).reload(root); |
| 177 | + }); |
| 178 | + var executeInSmartMode = DumbService.getInstance(project).isDumb(); |
| 179 | + if (executeInSmartMode) { |
| 180 | + action = action.inSmartMode(project); |
| 181 | + } |
| 182 | + action |
| 183 | + .submit(AppExecutorUtil.getAppExecutorService()); |
| 184 | + } |
| 185 | + |
| 186 | + private static void executeAction(Tree tree) { |
| 187 | + final TreePath path = tree.getSelectionPath(); |
| 188 | + Object node = path.getLastPathComponent(); |
| 189 | + if (node instanceof QuarkusActionNode) { |
| 190 | + ActionManager am = ActionManager.getInstance(); |
| 191 | + String actionId = ((QuarkusActionNode) node).getActionId(); |
| 192 | + if (actionId == null) { |
| 193 | + return; |
| 194 | + } |
| 195 | + AnAction action = am.getAction(actionId); |
| 196 | + if (action != null) { |
| 197 | + action.actionPerformed(new AnActionEvent(null, |
| 198 | + DataManager.getInstance().getDataContext(tree), |
| 199 | + ActionPlaces.UNKNOWN, new Presentation(), |
| 200 | + am, 0)); |
| 201 | + } |
| 202 | + |
| 203 | + } |
| 204 | + } |
| 205 | + |
| 206 | + @Override |
| 207 | + public void dispose() { |
| 208 | + |
| 209 | + } |
| 210 | +} |
0 commit comments