## 創建 plugin 專案
* 左側選單選取IDE Plugin

## 各檔案說明
* [**resource/META-INF/plugin.xml**](https://juejin.cn/post/6930813959775715336) -> plugin的設定檔
* id -> 這個plugin的唯一識別值(不能和其他的重複)
* name -> plugin名稱(在搜索時會出現的名稱)
* version -> 版本號
* vender -> 開發者主頁&email
* depends -> 依賴項
* ==actions== -> 控制點選功能以後對應到的java class
* id -> 唯一值
* class -> 對應到的java(點選後要執行的java class)
* text -> 顯示的名稱
* description -> 描述
* group-id -> plugin的功能鍵要顯示在哪裡
* anchor -> 功能鍵位置
* keyboard-shortcut -> 快捷鍵
``` xml
<action id="tw.sc.demo2.Hello" class="tw.sc.demo2.Hello" text="Hello" description="show Hello">
<add-to-group group-id="HelpMenu" anchor="first"/>
<keyboard-shortcut keymap="$default" first-keystroke="meta alt ENTER"/>
</action>
```
ps. https://blog.csdn.net/justry_deng/article/details/121874359 此網址為基礎建置教學,實測後照做可以正常執行,==內含常用group-id==
* **main/java/自定義**
* class 需要extends AnAction,並Override actionPerformed
* actionPerformed為plugin功能鍵點選後的直行進入點
* 以下程式碼為簡易的CreateGetController
```java
public class CreateGetController extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getProject();
if (project != null) {
// get editor
Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
if (editor != null) {
// insert code
WriteCommandAction.runWriteCommandAction(project, () -> {
int offset = editor.getCaretModel().getOffset();
String codeToInsert = generateControllerCode("get");
editor.getDocument().insertString(offset, codeToInsert);
});
}
}
}
private String generateControllerCode(String type) {
String controllerCode = "";
switch(type){
case "get":
default:
controllerCode = "@GetMapping(value = \"/\", produces = \"application/json\")\n" +
"public BaseModel Controller() {\n" +
" return new BaseModel();\n" +
"}";
break;
case "post":
controllerCode = "@PostMapping(value = \"/\", produces = \"application/json\")\n" +
"public BaseModel Controller() {\n" +
" return new BaseModel();\n" +
"}";
break;
}
return controllerCode;
}
}
```
## swing
* swing創建,創建後會有兩個檔案(java & form)

* form 檔用於拉介面,java檔跟介面相關的執行檔
* form拉的介面==要在對應的java中宣告==,且form中的field name要和宣告的變數名稱一樣
:point_down: 拉一個JText

:point_down: 左側的field name(form檔) ==要和宣告一樣==

:point_down: 宣告(java檔) ==要和field name一樣==

* **java**
* 要extends DialogWrapper,並Override createCenterPanel
``` java
public class CreateControllerClassDialog extends DialogWrapper {
@Override
protected @Nullable JComponent createCenterPanel() {
}
}
```
## 實作範例
* 自動寫入getController
:point_down: plugin.xml
``` xml
<group id="tw.sc.demo2.SCProd" text="_SCProd" description="SCProd">
<add-to-group group-id="EditorPopupMenu" anchor="last"/>
<action id="tw.sc.demo2.SCProd.CreateGetController" class="tw.sc.demo2.CreateGetController" text="CreateGetController" description="show Hello"/>
<add-to-group group-id="EditorPopupMenu" anchor="last"/>
<action id="tw.sc.demo2.Hello" class="tw.sc.demo2.Hello" text="Hello" description="show Hello">
<add-to-group group-id="HelpMenu" anchor="first"/>
</action>
</group>
```

:point_down: java
```java
public class CreateGetController extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
Project project = e.getProject();
if (project != null) {
// get editor
Editor editor = e.getRequiredData(CommonDataKeys.EDITOR);
if (editor != null) {
// insert code
WriteCommandAction.runWriteCommandAction(project, () -> {
int offset = editor.getCaretModel().getOffset();
String codeToInsert = generateControllerCode("get");
editor.getDocument().insertString(offset, codeToInsert);
});
}
}
}
private String generateControllerCode(String type) {
String controllerCode = "";
switch(type){
case "get":
default:
controllerCode = "@GetMapping(value = \"/\", produces = \"application/json\")\n" +
"public BaseModel Controller() {\n" +
" return new BaseModel();\n" +
"}";
break;
case "post":
controllerCode = "@PostMapping(value = \"/\", produces = \"application/json\")\n" +
"public BaseModel Controller() {\n" +
" return new BaseModel();\n" +
"}";
break;
}
return controllerCode;
}
}
```
* 自動創建java file
:point_down: plugin.xml
```xml
<action id="CreatePsiJavaFile"
class="tw.sc.demo2.action.CreateController"
text="Create Controller File">
<!-- 在 New 操作组的下面 -->
<add-to-group group-id="ProjectViewPopupMenu" anchor="after" relative-to-action="WeighingNewGroup"/>
<!--快捷鍵-->
<!-- <keyboard-shortcut keymap="$default" first-keystroke="meta alt ENTER"/>-->
</action>
```
:point_down: java
```java
public class CreateController extends AnAction {
@Override
public void actionPerformed(@NotNull AnActionEvent e) {
PsiElement psiElement =e.getData(CommonDataKeys.PSI_ELEMENT);
PsiDirectory psiDirectory;
if (psiElement instanceof PsiDirectory) {
psiDirectory = (PsiDirectory) psiElement;
} else {
psiDirectory = psiElement.getContainingFile().getContainingDirectory();
}
new CreateControllerClassDialog(psiDirectory).show();
}
}
```
:point_down: swing的java ==目前僅能新建一個java檔,但程式碼邏輯內包含新建class、constructor等,但尚未成功==
```java
public class CreateControllerClassDialog extends DialogWrapper {
private final boolean createState;
private Project myProject;
private PsiDirectory myPsiDirectory;
private JPanel mainPanel;
private JLabel classNameLabel;
private JTextField className;
public CreateControllerClassDialog(@Nonnull PsiDirectory directory) {
super(true);
createState = true;
setTitle("create.java.file");// 對話框標題
myPsiDirectory = directory;
myProject = myPsiDirectory.getProject();
init();
}
@Override
protected @Nullable JComponent createCenterPanel() {
mainPanel = new JPanel(new BorderLayout());
// 初始化
classNameLabel = new JLabel("Class Name: ");
className = new JTextField();
// 把組件加到mainPanel
mainPanel.add(classNameLabel, BorderLayout.WEST);
mainPanel.add(className, BorderLayout.CENTER);
// // 如果是 Class 展示添加 @Data 注解的???
// types.addItemListener(l -> dataPane.setVisible(l.getItem().equals(ClassType.Class)));
return mainPanel;
}
public String getClassName() {
return className.getText();
}
@Override
protected void doOKAction() {
if (createState) {
createJavaFile();
} else {
// editJavaFile();
}
// 關閉視窗
super.doOKAction();
}
private void createJavaFile() {
String classNameText = className.getText();
// use WriteCommandAction to do not-read(create、edit、delete)
WriteCommandAction.runWriteCommandAction(myProject, "create.java.file", "Psi", () -> {
try {
PsiFile javaFile = myPsiDirectory.createFile(classNameText + ".java");
// 添加 PsiClass 到 PsiFile
PsiClass psiClass = JavaDirectoryService.getInstance().createClass(myPsiDirectory, classNameText);
// 在 PsiClass 中加入code
addCodeToPsiClass(psiClass);
javaFile.add(psiClass);
// 添加 PsiFile 到 PsiDirectory
myPsiDirectory.add(javaFile);
} catch (Exception exception) {
exception.printStackTrace();
}
});
}
private void addCodeToPsiClass(PsiClass psiClass) {
String classCode = "public class MyClass {\n" +
" // 添加方法\n" +
" public void myMethod() {\n" +
" // Your code here\n" +
" }\n" +
"\n" +
" // 添加constructor\n" +
" public MyClass() {\n" +
" // Your code here\n" +
" }\n" +
"}\n";
// 使用 PsiElementFactory 建 PsiClass
PsiElementFactory elementFactory = JavaPsiFacade.getElementFactory(myProject);
PsiClass newClass = elementFactory.createClassFromText(classCode, null);
// 取文件的大括號的位置
PsiElement lBrace = psiClass.getLBrace();
PsiElement rBrace = psiClass.getRBrace();
// 新建的添加到文件的大括號中
if (lBrace != null && rBrace != null) {
psiClass.addBefore(newClass, rBrace);
}
}
public enum ClassType {
Class, Interface, Enum
}
}
```
:point_down: swing的form

## 參考資料
* https://zhuanlan.zhihu.com/p/400059601?utm_id=0 -> 內含github,實測過後可使用
* https://blog.csdn.net/justry_deng/article/details/121874359 -> 初步教學
* https://www.cnblogs.com/Jcloud/p/17510682.html -> 後半段是較為進階的教學