1 /*
2  * Copyright (C) 2019 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.android.atest.toolWindow;
17 
18 import com.android.atest.AtestUtils;
19 import com.android.atest.Constants;
20 import com.android.atest.commandAdapter.CommandRunner;
21 import com.android.atest.dialog.MessageDialog;
22 import com.android.atest.widget.AtestFastInputController;
23 import com.android.atest.widget.AtestNotification;
24 import com.intellij.notification.Notifications;
25 import com.intellij.openapi.diagnostic.Logger;
26 import com.intellij.openapi.project.Project;
27 import com.intellij.openapi.wm.ToolWindow;
28 import com.intellij.openapi.wm.ToolWindowManager;
29 import com.intellij.openapi.wm.ex.ToolWindowEx;
30 import com.intellij.openapi.wm.impl.ToolWindowImpl;
31 import org.jetbrains.annotations.NotNull;
32 
33 import javax.swing.*;
34 import java.awt.*;
35 
36 /** UI content of Atest tool window. */
37 public class AtestToolWindow {
38 
39     private static final int INITIAL_WIDTH = 1000;
40     private static final Logger LOG = Logger.getInstance(AtestToolWindow.class);
41     private static AtestToolWindow sAtestToolWindowInstance;
42 
43     private JPanel mAtestToolWindowPanel;
44     private JScrollPane mScorll;
45     private JLabel mAtestlabel;
46     private JTextField mLunchTarget;
47     private JCheckBox mRunOnHost;
48     private JCheckBox mTestMapping;
49     private JCheckBox mSkipBuild;
50     private JButton mRunButton;
51     private JComboBox mTestTarget;
52     private JButton mStopButton;
53     private Project mProject;
54 
55     /**
56      * Initializes AtestToolWindow with ToolWindow and Project.
57      *
58      * @param toolWindow a child window of the IDE used to display information.
59      * @param project the current intelliJ project.
60      */
AtestToolWindow(ToolWindow toolWindow, Project project)61     private AtestToolWindow(ToolWindow toolWindow, Project project) {
62         mProject = project;
63         String basePath = project.getBasePath();
64         setInitialWidth((ToolWindowEx) toolWindow);
65         setRunButton(basePath);
66         setStopButton();
67         initTestTarget(basePath);
68         AtestFastInputController fastInputController =
69                 new AtestFastInputController(mTestTarget, mRunOnHost, mTestMapping, mSkipBuild);
70         fastInputController.linkCheckBoxWithTestTarget();
71     }
72 
73     /**
74      * Initializes AtestToolWindow instance.
75      *
76      * <p>Because the AtestToolWindow should be modified when the project is changed. It can't be
77      * singleton. This initializer is used by the ToolWindowFactory. We use IntelliJ's mechanism to
78      * make sure AtestToolWindow's instance can always follow the project.
79      *
80      * @param toolWindow a child window of the IDE used to display information.
81      * @param project the current intelliJ project.
82      * @return the AtestToolWindow instance.
83      */
84     @NotNull
initAtestToolWindow(ToolWindow toolWindow, Project project)85     public static AtestToolWindow initAtestToolWindow(ToolWindow toolWindow, Project project) {
86         sAtestToolWindowInstance = new AtestToolWindow(toolWindow, project);
87         return sAtestToolWindowInstance;
88     }
89 
90     /**
91      * Gets AtestToolWindow instance by project.
92      *
93      * <p>When using ToolWindowManager to get atest tool window, it will initialize the
94      * AtestToolWindow by {@link AtestToolWindowFactory} asynchronously. We use
95      * ensureContentInitialized from ToolWindowImpl to ensure the AtestToolWindow has been
96      * initialized.
97      *
98      * @param project the current intelliJ project.
99      * @return the AtestToolWindow instance.
100      */
101     @NotNull
getInstance(@otNull Project project)102     public static AtestToolWindow getInstance(@NotNull Project project) {
103         ToolWindow AtestTW =
104                 ToolWindowManager.getInstance(project).getToolWindow(Constants.ATEST_TOOL_WINDOW);
105         if (AtestTW instanceof ToolWindowImpl) {
106             ((ToolWindowImpl) AtestTW).ensureContentInitialized();
107         }
108 
109         if (sAtestToolWindowInstance == null) {
110             LOG.error("AtestToolWindowInstance is null when getting instance by project");
111             Notifications.Bus.notify(new AtestNotification(Constants.ATEST_WINDOW_FAIL));
112         }
113         return sAtestToolWindowInstance;
114     }
115 
116     /**
117      * Initializes mTestTarget.
118      *
119      * @param basePath a string that represents current project's base path.
120      */
initTestTarget(String basePath)121     private void initTestTarget(String basePath) {
122         mTestTarget.setEditable(true);
123         if (AtestUtils.hasTestMapping(basePath)) {
124             mTestTarget.setSelectedItem(basePath);
125         }
126     }
127 
128     /**
129      * Sets the initial width of the tool window.
130      *
131      * @param toolWindowEx a toolWindow which has more methods.
132      */
setInitialWidth(@otNull ToolWindowEx toolWindowEx)133     private void setInitialWidth(@NotNull ToolWindowEx toolWindowEx) {
134         int width = toolWindowEx.getComponent().getWidth();
135         if (width < INITIAL_WIDTH) {
136             toolWindowEx.stretchWidth(INITIAL_WIDTH - width);
137         }
138     }
139 
140     /** Initializes the run button. */
setRunButton(String basePath)141     private void setRunButton(String basePath) {
142         // When command running, the run button will be set to disable, then the focus will set to
143         // next object. Set run button not focusable to prevent it.
144         mRunButton.setFocusable(false);
145         mRunButton.addActionListener(
146                 e -> {
147                     String lunchTarget = mLunchTarget.getText();
148                     String testTarget = mTestTarget.getEditor().getItem().toString();
149                     String workPath = AtestUtils.getAndroidRoot(basePath);
150                     try {
151                         CommandRunner runner =
152                                 new CommandRunner(
153                                         lunchTarget,
154                                         testTarget,
155                                         workPath,
156                                         AtestToolWindow.this,
157                                         mProject);
158                         runner.run();
159                     } catch (IllegalArgumentException exception) {
160                         String errorMessage =
161                                 AtestUtils.checkError(lunchTarget, testTarget, workPath);
162                         MessageDialog.showMessageDialog(errorMessage);
163                     }
164                 });
165     }
166 
167     /** Initializes the stop button. */
setStopButton()168     private void setStopButton() {
169         mStopButton.addActionListener(
170                 e -> {
171                     CommandRunner.stopProcess(mProject);
172                 });
173     }
174 
175     /** Scrolls the output window scroll bar to the bottom. */
scrollToEnd()176     public void scrollToEnd() {
177         JScrollBar vertical = mScorll.getVerticalScrollBar();
178         vertical.setValue(vertical.getMaximum());
179     }
180 
181     /**
182      * Enables (or disables) the run button.
183      *
184      * @param isEnable true to enable the run button, otherwise disable it.
185      */
setRunEnable(boolean isEnable)186     public void setRunEnable(boolean isEnable) {
187         mRunButton.setEnabled(isEnable);
188     }
189 
190     /**
191      * Gets the UI panel of Atest tool window.
192      *
193      * @return the JPanel of Atest tool window.
194      */
getContent()195     public JPanel getContent() {
196         return mAtestToolWindowPanel;
197     }
198 
199     /**
200      * Sets the test target of Atest tool window.
201      *
202      * @param target the test target of Atest tool window.
203      */
setTestTarget(@otNull String target)204     public void setTestTarget(@NotNull String target) {
205         mTestTarget.setSelectedItem(target);
206     }
207 
208     /**
209      * Sets the lunch target of Atest tool window.
210      *
211      * @param target the lunch target of Atest tool window.
212      */
setLunchTarget(@otNull String target)213     public void setLunchTarget(@NotNull String target) {
214         mLunchTarget.setText(target);
215     }
216 }
217