├── .github
└── ISSUE_TEMPLATE
│ └── bug_report.md
├── .gitignore
├── CHANGELOG.md
├── LICENSE
├── README.md
├── README_EN.md
├── build.gradle
├── gradle
└── wrapper
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
├── images
├── install1.png
├── mvp.gif
├── settings.png
├── settings1.png
├── use1.png
├── use2.png
├── use3.png
└── use4.png
├── settings.gradle
└── src
└── main
├── java
└── com
│ └── longforus
│ └── mvpautocodeplus
│ ├── Utils.java
│ └── ui
│ ├── ConfigForm.form
│ ├── ConfigForm.java
│ ├── EnterKeywordDialog.form
│ └── EnterKeywordDialog.java
├── kotlin
└── com
│ └── longforus
│ └── mvpautocodeplus
│ ├── Cons.kt
│ ├── Extfun.kt
│ ├── MainAction.kt
│ ├── TemplateCons.java
│ ├── config
│ ├── ConfigComponent.kt
│ └── ItemConfigBean.kt
│ └── maker
│ ├── CodeMaker.kt
│ ├── ComponentRegister.kt
│ ├── FileMaker.kt
│ ├── LayoutCreator.kt
│ ├── MethodImpl.kt
│ ├── TemplateMaker.kt
│ └── TemplateParamFactory.kt
└── resources
└── META-INF
└── plugin.xml
/.github/ISSUE_TEMPLATE/bug_report.md:
--------------------------------------------------------------------------------
1 | ---
2 | name: Bug report
3 | about: Create a report to help us improve
4 |
5 | ---
6 |
7 | **Describe the bug**
8 | A clear and concise description of what the bug is.
9 |
10 | **Screenshots**
11 | If applicable, add screenshots to help explain your problem.
12 | - Plugin config :
13 |
14 | - Package structure :
15 |
16 | **Error log**
17 |
18 | **Desktop (please complete the following information):**
19 | - OS Version: [e.g. Win10]
20 | - Android Studio Version [e.g. 3.1.3]
21 | - Plugin Version [e.g. 1.1.0]
22 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # Created by .ignore support plugin (hsz.mobi)
2 | ### Kotlin template
3 | # Compiled class file
4 | *.class
5 |
6 | # Log file
7 | *.log
8 |
9 | # BlueJ files
10 | *.ctxt
11 |
12 | # Mobile Tools for Java (J2ME)
13 | .mtj.tmp/
14 |
15 | # Package Files #
16 | *.jar
17 | *.war
18 | *.ear
19 | *.zip
20 | *.tar.gz
21 | *.rar
22 |
23 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml
24 | hs_err_pid*
25 | ### JetBrains template
26 | # Covers JetBrains IDEs: IntelliJ, RubyMine, PhpStorm, AppCode, PyCharm, CLion, Android Studio and WebStorm
27 | # Reference: https://intellij-support.jetbrains.com/hc/en-us/articles/206544839
28 |
29 | # CMake
30 | cmake-build-debug/
31 | cmake-build-release/
32 |
33 |
34 |
35 | ## File-based project format:
36 | *.iws
37 |
38 | ## Plugin-specific files:
39 |
40 | # IntelliJ
41 | out/
42 | build/
43 | .gradle/
44 | .idea/
45 | # mpeltonen/sbt-idea plugin
46 | .idea_modules/
47 |
48 | # JIRA plugin
49 | atlassian-ide-plugin.xml
50 |
51 |
52 | # Crashlytics plugin (for Android Studio and IntelliJ)
53 | com_crashlytics_export_strings.xml
54 | crashlytics.properties
55 | crashlytics-build.properties
56 | fabric.properties
57 | gradle.properties
58 | /local.properties
59 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 |
3 |
4 | ## [v1.4.5](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2020-10-17)
5 | - Adapter Android studio 4.1,fix create layout file error.
6 |
7 | ## [v1.4.4](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2020-9-27)
8 | - Fix Bug: Import R File package name incorrect
9 |
10 | ## [v1.4.3](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2020-6-4)
11 | - Adapter Android studio 4.0
12 |
13 | ## [v1.4.2](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2020-4-25)
14 | - Add layout file create.
15 | - Add activity auto manifest register
16 | - We plan to add viewBinding support, but have not yet found a suitable implementation
17 |
18 | ## [v1.4.1](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2019-9-8)
19 | - Fix Android studio 3.5+ menu text.
20 |
21 | ## [v1.4](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2019-6-16)
22 | - Add ViewModel name support,now if super Presenter interface name endsWith ViewModel,generated presenter name is also ViewModel.
23 |
24 | ## [v1.3](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2018-11-27)
25 | - Fix bug.
26 | - Support custom super interface name..
27 |
28 | ## [v1.2](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2018-11-27)
29 |
30 | - Add generate model checkbox state save.
31 | - Change file template format.
32 | - Add Android Studio 3.4 support.
33 | - Fix bug.
34 |
35 | ## [v1.1](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2018-9-11)
36 |
37 | - Support for not generating Model interfaces and corresponding implementation classes , is more flexible.
38 |
39 | ## [v1.0-183](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2018-8-14)
40 |
41 | - 添加IDEA 2018.2 和 AndroidStudio 3.3的支持.
42 |
43 | ## [v1.0](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2018-7-16)
44 |
45 | - 添加兼容性配置,正式版发布.
46 |
47 | ## [v1.0-beat2](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2018-7-10)
48 |
49 | - 添加配置界面的Class选择支持
50 | - 配置文件增加全局和当前项目模式,可随意选择使用全局配置或当前项目配置.
51 |
52 | ## [v1.0-beat1](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2018-7-5)
53 |
54 | - 结合新版的mvp接口做出调整
55 | - 修改Kotlin实现类名字错误的bug
56 | - 添加 P,M 无父类的生成策略实现
57 |
58 |
59 | ## [v1.0-beat](https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus)(2018-7-4)
60 |
61 | - 完成Contract的生成
62 | - 完成Java实现类的生成,及抽象方法的默认实现
63 | - 完成Kotlin实现类的生成,及抽象方法的默认实现
64 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | Apache License
2 | Version 2.0, January 2004
3 | http://www.apache.org/licenses/
4 |
5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
6 |
7 | 1. Definitions.
8 |
9 | "License" shall mean the terms and conditions for use, reproduction,
10 | and distribution as defined by Sections 1 through 9 of this document.
11 |
12 | "Licensor" shall mean the copyright owner or entity authorized by
13 | the copyright owner that is granting the License.
14 |
15 | "Legal Entity" shall mean the union of the acting entity and all
16 | other entities that control, are controlled by, or are under common
17 | control with that entity. For the purposes of this definition,
18 | "control" means (i) the power, direct or indirect, to cause the
19 | direction or management of such entity, whether by contract or
20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the
21 | outstanding shares, or (iii) beneficial ownership of such entity.
22 |
23 | "You" (or "Your") shall mean an individual or Legal Entity
24 | exercising permissions granted by this License.
25 |
26 | "Source" form shall mean the preferred form for making modifications,
27 | including but not limited to software source code, documentation
28 | source, and configuration files.
29 |
30 | "Object" form shall mean any form resulting from mechanical
31 | transformation or translation of a Source form, including but
32 | not limited to compiled object code, generated documentation,
33 | and conversions to other media types.
34 |
35 | "Work" shall mean the work of authorship, whether in Source or
36 | Object form, made available under the License, as indicated by a
37 | copyright notice that is included in or attached to the work
38 | (an example is provided in the Appendix below).
39 |
40 | "Derivative Works" shall mean any work, whether in Source or Object
41 | form, that is based on (or derived from) the Work and for which the
42 | editorial revisions, annotations, elaborations, or other modifications
43 | represent, as a whole, an original work of authorship. For the purposes
44 | of this License, Derivative Works shall not include works that remain
45 | separable from, or merely link (or bind by name) to the interfaces of,
46 | the Work and Derivative Works thereof.
47 |
48 | "Contribution" shall mean any work of authorship, including
49 | the original version of the Work and any modifications or additions
50 | to that Work or Derivative Works thereof, that is intentionally
51 | submitted to Licensor for inclusion in the Work by the copyright owner
52 | or by an individual or Legal Entity authorized to submit on behalf of
53 | the copyright owner. For the purposes of this definition, "submitted"
54 | means any form of electronic, verbal, or written communication sent
55 | to the Licensor or its representatives, including but not limited to
56 | communication on electronic mailing lists, source code control systems,
57 | and issue tracking systems that are managed by, or on behalf of, the
58 | Licensor for the purpose of discussing and improving the Work, but
59 | excluding communication that is conspicuously marked or otherwise
60 | designated in writing by the copyright owner as "Not a Contribution."
61 |
62 | "Contributor" shall mean Licensor and any individual or Legal Entity
63 | on behalf of whom a Contribution has been received by Licensor and
64 | subsequently incorporated within the Work.
65 |
66 | 2. Grant of Copyright License. Subject to the terms and conditions of
67 | this License, each Contributor hereby grants to You a perpetual,
68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
69 | copyright license to reproduce, prepare Derivative Works of,
70 | publicly display, publicly perform, sublicense, and distribute the
71 | Work and such Derivative Works in Source or Object form.
72 |
73 | 3. Grant of Patent License. Subject to the terms and conditions of
74 | this License, each Contributor hereby grants to You a perpetual,
75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable
76 | (except as stated in this section) patent license to make, have made,
77 | use, offer to sell, sell, import, and otherwise transfer the Work,
78 | where such license applies only to those patent claims licensable
79 | by such Contributor that are necessarily infringed by their
80 | Contribution(s) alone or by combination of their Contribution(s)
81 | with the Work to which such Contribution(s) was submitted. If You
82 | institute patent litigation against any entity (including a
83 | cross-claim or counterclaim in a lawsuit) alleging that the Work
84 | or a Contribution incorporated within the Work constitutes direct
85 | or contributory patent infringement, then any patent licenses
86 | granted to You under this License for that Work shall terminate
87 | as of the date such litigation is filed.
88 |
89 | 4. Redistribution. You may reproduce and distribute copies of the
90 | Work or Derivative Works thereof in any medium, with or without
91 | modifications, and in Source or Object form, provided that You
92 | meet the following conditions:
93 |
94 | (a) You must give any other recipients of the Work or
95 | Derivative Works a copy of this License; and
96 |
97 | (b) You must cause any modified files to carry prominent notices
98 | stating that You changed the files; and
99 |
100 | (c) You must retain, in the Source form of any Derivative Works
101 | that You distribute, all copyright, patent, trademark, and
102 | attribution notices from the Source form of the Work,
103 | excluding those notices that do not pertain to any part of
104 | the Derivative Works; and
105 |
106 | (d) If the Work includes a "NOTICE" text file as part of its
107 | distribution, then any Derivative Works that You distribute must
108 | include a readable copy of the attribution notices contained
109 | within such NOTICE file, excluding those notices that do not
110 | pertain to any part of the Derivative Works, in at least one
111 | of the following places: within a NOTICE text file distributed
112 | as part of the Derivative Works; within the Source form or
113 | documentation, if provided along with the Derivative Works; or,
114 | within a display generated by the Derivative Works, if and
115 | wherever such third-party notices normally appear. The contents
116 | of the NOTICE file are for informational purposes only and
117 | do not modify the License. You may add Your own attribution
118 | notices within Derivative Works that You distribute, alongside
119 | or as an addendum to the NOTICE text from the Work, provided
120 | that such additional attribution notices cannot be construed
121 | as modifying the License.
122 |
123 | You may add Your own copyright statement to Your modifications and
124 | may provide additional or different license terms and conditions
125 | for use, reproduction, or distribution of Your modifications, or
126 | for any such Derivative Works as a whole, provided Your use,
127 | reproduction, and distribution of the Work otherwise complies with
128 | the conditions stated in this License.
129 |
130 | 5. Submission of Contributions. Unless You explicitly state otherwise,
131 | any Contribution intentionally submitted for inclusion in the Work
132 | by You to the Licensor shall be under the terms and conditions of
133 | this License, without any additional terms or conditions.
134 | Notwithstanding the above, nothing herein shall supersede or modify
135 | the terms of any separate license agreement you may have executed
136 | with Licensor regarding such Contributions.
137 |
138 | 6. Trademarks. This License does not grant permission to use the trade
139 | names, trademarks, service marks, or product names of the Licensor,
140 | except as required for reasonable and customary use in describing the
141 | origin of the Work and reproducing the content of the NOTICE file.
142 |
143 | 7. Disclaimer of Warranty. Unless required by applicable law or
144 | agreed to in writing, Licensor provides the Work (and each
145 | Contributor provides its Contributions) on an "AS IS" BASIS,
146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
147 | implied, including, without limitation, any warranties or conditions
148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
149 | PARTICULAR PURPOSE. You are solely responsible for determining the
150 | appropriateness of using or redistributing the Work and assume any
151 | risks associated with Your exercise of permissions under this License.
152 |
153 | 8. Limitation of Liability. In no event and under no legal theory,
154 | whether in tort (including negligence), contract, or otherwise,
155 | unless required by applicable law (such as deliberate and grossly
156 | negligent acts) or agreed to in writing, shall any Contributor be
157 | liable to You for damages, including any direct, indirect, special,
158 | incidental, or consequential damages of any character arising as a
159 | result of this License or out of the use or inability to use the
160 | Work (including but not limited to damages for loss of goodwill,
161 | work stoppage, computer failure or malfunction, or any and all
162 | other commercial damages or losses), even if such Contributor
163 | has been advised of the possibility of such damages.
164 |
165 | 9. Accepting Warranty or Additional Liability. While redistributing
166 | the Work or Derivative Works thereof, You may choose to offer,
167 | and charge a fee for, acceptance of support, warranty, indemnity,
168 | or other liability obligations and/or rights consistent with this
169 | License. However, in accepting such obligations, You may act only
170 | on Your own behalf and on Your sole responsibility, not on behalf
171 | of any other Contributor, and only if You agree to indemnify,
172 | defend, and hold each Contributor harmless for any liability
173 | incurred by, or claims asserted against, such Contributor by reason
174 | of your accepting any such warranty or additional liability.
175 |
176 | END OF TERMS AND CONDITIONS
177 |
178 | APPENDIX: How to apply the Apache License to your work.
179 |
180 | To apply the Apache License to your work, attach the following
181 | boilerplate notice, with the fields enclosed by brackets "[]"
182 | replaced with your own identifying information. (Don't include
183 | the brackets!) The text should be enclosed in the appropriate
184 | comment syntax for the file format. We also recommend that a
185 | file or class name and description of purpose be included on the
186 | same "printed page" as the copyright notice for easier
187 | identification within third-party archives.
188 |
189 | Copyright [Void Young] [https://github.com/longforus yxq.longforus@gmail.com]
190 |
191 | Licensed under the Apache License, Version 2.0 (the "License");
192 | you may not use this file except in compliance with the License.
193 | You may obtain a copy of the License at
194 |
195 | http://www.apache.org/licenses/LICENSE-2.0
196 |
197 | Unless required by applicable law or agreed to in writing, software
198 | distributed under the License is distributed on an "AS IS" BASIS,
199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
200 | See the License for the specific language governing permissions and
201 | limitations under the License.
202 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | MvpAutoCodePlus
4 | =================
5 | 基于 MvpAutoCodePlus 开发
6 | https://github.com/longforus/MvpAutoCodePlus
7 |
--------------------------------------------------------------------------------
/README_EN.md:
--------------------------------------------------------------------------------
1 | MvpAutoCodePlus
2 | ========================
3 |
4 | [![Downloads][downloads-img]][plugin]
5 |
6 | JetBrains IDEA/Android Studio MVP template code generation plug-in
7 |
8 | 
9 |
10 | ## Character
11 |
12 | - generate the MVP Contract interface class based on the specified parent interface.
13 | - optionally generate an MVP implementation class based on the generated MVP Contract and the specified parent class, and add an abstract method default implementation.
14 | - support Activity
15 | - support fragments
16 | - support the Presenter
17 | - support the Model
18 | - support Java and Kotlin languages
19 |
20 | ## IDE support:
21 |
22 | - Android Studio(supported from 3.1(173.3727-173.*))
23 | - IntelliJ IDEA
24 | - IntelliJ IDEA Community Edition
25 |
26 | ## The installation
27 |
28 | - **install using the IDE built-in plug-in system :**
29 |
30 | - File > Preferences(Settings) > Plugins > Browse repositories... > search and find "MvpAutoCodePlus" > Install Plugin
31 |
32 | 
33 |
34 | - **manual installation :**
35 | [`download the latest release of plug-in package `][latest-release] - > File >Preferences(Settings) > Plugins > Install plugin from disk...
36 |
37 | - **Restart the IDE**.
38 |
39 | ## Usage
40 |
41 | 1. Configure the parent interface:
42 |
43 | - File > Preferences(Settings) > Other Settings > MvpAutoCodePlus >
44 |
45 | 
46 |
47 | Based on [`this a set of Java interfaces`][my_interface_java] example configuration:
48 |
49 | 
50 |
51 | Project in the Class has been V1.0beta2 support to choose, but if there are generic limit, generic or need to manually add, such as the choice of Class signature is: **com.longforus.Base.Java.BasePresenterJv**
52 |
53 | 
54 |
55 | Manually add the following generic qualifier :
56 |
57 | 
58 |
59 | Global and current project modes are also supported, and the interfaces configured in global mode can be used in all projects. The interfaces configured in the current project only work in the current project, facilitating seamless switching between multiple different projects.
60 |
61 | 2. Generate:
62 |
63 | 
64 |
65 | - right click the target package to be generated,New > Generate Mvp Code (or select the package, press Alt+Insert). After generating the contract package, you can select the parent package of the contract package or contract.
66 | - enter the code generated by the name, such as do the Login function, enter the Login and generate results is ILoginContract, LoginActivity, LoginPresenter, LoginModel
67 | - choose the code implementation, Java or Kotlin
68 | - select the implementation method of View,Activity or Fragment. If there are multiple configurations, select one of them, and remove the previous check box for the items you don't want to generate. If there are no superclasses of P and M implementation classes, the generated implementation classes of P and M will only implement the corresponding interface.
69 | - Support for not generating Model interfaces and corresponding implementation classes from 1.1 onwards is more flexible.
70 | - click Ok, wait a moment, and the code is generated. The generated package structure is as follows:
71 |
72 | 
73 |
74 | ## About the parent interface
75 |
76 | Only use my own currently use interface to development and testing, welcome to use their own interface for testing. If need [` I use interface `][my_interface], please download it in your own project.
77 |
78 | ## Problem
79 |
80 | - if the parent interface and the parent class have a generic qualifier, you will need to manually enter the generic after selecting it, but it will be saved only once set and will not change frequently in the project.
81 |
82 | - we haven't studied the layout file corresponding to the View, and it would be more convenient if we could also generate the default.
83 |
84 | - other unknown problems, this plug-in is the first time for the author to develop the plug-in, which is completely from 0. The official documents are not very detailed, and the English level is even worse.
85 |
86 | [complete update history](./changelog.md)
87 |
88 | if do not meet the requirements of your plugin. Can issue, also can fork to modify. Thank you for your attention.
89 |
90 | [latest-release]: https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus
91 | [downloads-img]: https://img.shields.io/jetbrains/plugin/d/8579.svg?style=flat-square
92 | [plugin]: https://plugins.jetbrains.com/plugin/10907-mvpautocodeplus
93 | [my_interface]:https://github.com/longforus/MVPExample
94 | [my_interface_java]:https://github.com/longforus/MVPExample/tree/master/app/src/main/java/com/longforus/base/java
95 |
--------------------------------------------------------------------------------
/build.gradle:
--------------------------------------------------------------------------------
1 | buildscript {
2 | // ext.kotlin_version = '1.5.10'
3 | ext.kotlin_version = '1.4.21'
4 | repositories {
5 | // maven { url 'http://192.168.2.39:8908/repository/maven-public/' }
6 | maven { url 'https://maven.aliyun.com/repository/public' }
7 | google()
8 | mavenCentral()
9 | maven {url 'https://dl.google.com/dl/android/maven2/'}
10 | }
11 | dependencies {
12 | classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
13 | }
14 | }
15 |
16 | plugins {
17 | id 'org.jetbrains.intellij' version '0.4.2'
18 | // id 'org.jetbrains.intellij' version '1.0'
19 | }
20 |
21 | version '1.4.5'
22 | group 'com.longforus'
23 |
24 | apply plugin: 'java'
25 | apply plugin: 'kotlin'
26 | apply plugin: 'kotlin-kapt'
27 | apply plugin: 'org.jetbrains.intellij'
28 |
29 | sourceCompatibility = 1.8
30 | targetCompatibility = 1.8
31 |
32 | //sourceSets {
33 | // main {
34 | // java {
35 | // srcDir "${project.rootDir.absolutePath}/thirdParty/javapoet/java/src"
36 | // }
37 | // }
38 | //}
39 |
40 | repositories {
41 | // maven{ url 'http://192.168.2.39:8908/repository/maven-public/'}
42 | maven { url 'https://maven.aliyun.com/repository/public' }
43 | google()
44 | mavenCentral()
45 | maven {url 'https://dl.google.com/dl/android/maven2/'}
46 | }
47 |
48 | compileKotlin {
49 | kotlinOptions.jvmTarget = "1.8"
50 | }
51 | compileTestKotlin {
52 | kotlinOptions.jvmTarget = "1.8"
53 | }
54 |
55 | if (!hasProperty('StudioCompilePath')) {
56 | throw new GradleException("No StudioCompilePath value was set, please create gradle.properties file")
57 | }
58 |
59 | intellij {
60 |
61 | plugins 'java'
62 |
63 | version '2019.3'
64 | plugins "org.jetbrains.kotlin:1.3.72-release-IJ2019.3-1" //here
65 | // plugins 'org.jetbrains.kotlin:1.3.21-release-IJ2018.2-1' //here
66 | // version '2018.2'
67 | // plugins 'org.jetbrains.kotlin:1.2.61-release-IJ2018.2-1' //here
68 | // version '2018.1'
69 | // plugins 'org.jetbrains.kotlin:1.2.60-release-IJ2018.1-1' //here
70 | // version '2017.3'
71 | // plugins 'org.jetbrains.kotlin:1.2.61-release-IJ2017.3-1' //here
72 | intellij.updateSinceUntilBuild false
73 | // intellij.localPath = project.hasProperty("StudioRunPath") ? StudioRunPath : StudioCompilePath
74 | }
75 |
76 | dependencies {
77 | compile "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
78 | compileOnly fileTree(dir: "$StudioCompilePath/plugins/android/lib", include: ['*.jar'])
79 | compileOnly fileTree(dir: "$StudioCompilePath/plugins/java/lib", include: ['*.jar'])
80 | compileOnly fileTree(dir: "$StudioCompilePath/lib", include: ['*.jar'])
81 |
82 | testCompile fileTree(dir: "$StudioCompilePath/plugins/android/lib", include: ['*.jar'])
83 | testCompile fileTree(dir: "$StudioCompilePath/plugins/java/lib", include: ['*.jar'])
84 | testCompile fileTree(dir: "$StudioCompilePath/lib", include: ['*.jar'])
85 | // compile "com.jetbrains.intellij.java:java-psi:192.7142.36"
86 | // compileOnly "com.android.tools.build:gradle:3.6.1"
87 | compileOnly "com.android.tools.build:gradle:4.0.1"
88 | // compileOnly "com.jetbrains.intellij.java:java:192.7142.36"
89 | // compile 'com.squareup:javapoet:1.11.0'
90 | // testCompile group: 'junit', name: 'junit', version: '4.12'
91 | }
92 |
93 | patchPluginXml {
94 | changeNotes """Adapter Android studio 4.1,fix create layout file error.
95 |
96 | Full Changelog History"""
97 | }
98 |
99 | //publishPlugin {
100 | // token publishToken
101 | //}
102 |
103 | //指定编译的编码
104 | tasks.withType(JavaCompile) {
105 | options.encoding = "UTF-8"
106 | }
107 |
108 | task verifySetup() {
109 | doLast {
110 | def ideaJar = "$StudioCompilePath/lib/idea.jar"
111 | if (!file(ideaJar).exists()) {
112 | throw new GradleException("$ideaJar not found, set StudioCompilePath in gradle.properties")
113 | }
114 | }
115 | }
116 |
117 | compileJava.dependsOn verifySetup
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | #Sun Jun 16 18:35:34 CST 2019
2 | distributionBase=GRADLE_USER_HOME
3 | distributionPath=wrapper/dists
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 | distributionUrl=https\://services.gradle.org/distributions/gradle-6.7.1-all.zip
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env sh
2 |
3 | ##############################################################################
4 | ##
5 | ## Gradle start up script for UN*X
6 | ##
7 | ##############################################################################
8 |
9 | # Attempt to set APP_HOME
10 | # Resolve links: $0 may be a link
11 | PRG="$0"
12 | # Need this for relative symlinks.
13 | while [ -h "$PRG" ] ; do
14 | ls=`ls -ld "$PRG"`
15 | link=`expr "$ls" : '.*-> \(.*\)$'`
16 | if expr "$link" : '/.*' > /dev/null; then
17 | PRG="$link"
18 | else
19 | PRG=`dirname "$PRG"`"/$link"
20 | fi
21 | done
22 | SAVED="`pwd`"
23 | cd "`dirname \"$PRG\"`/" >/dev/null
24 | APP_HOME="`pwd -P`"
25 | cd "$SAVED" >/dev/null
26 |
27 | APP_NAME="Gradle"
28 | APP_BASE_NAME=`basename "$0"`
29 |
30 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
31 | DEFAULT_JVM_OPTS=""
32 |
33 | # Use the maximum available, or set MAX_FD != -1 to use that value.
34 | MAX_FD="maximum"
35 |
36 | warn () {
37 | echo "$*"
38 | }
39 |
40 | die () {
41 | echo
42 | echo "$*"
43 | echo
44 | exit 1
45 | }
46 |
47 | # OS specific support (must be 'true' or 'false').
48 | cygwin=false
49 | msys=false
50 | darwin=false
51 | nonstop=false
52 | case "`uname`" in
53 | CYGWIN* )
54 | cygwin=true
55 | ;;
56 | Darwin* )
57 | darwin=true
58 | ;;
59 | MINGW* )
60 | msys=true
61 | ;;
62 | NONSTOP* )
63 | nonstop=true
64 | ;;
65 | esac
66 |
67 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
68 |
69 | # Determine the Java command to use to start the JVM.
70 | if [ -n "$JAVA_HOME" ] ; then
71 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
72 | # IBM's JDK on AIX uses strange locations for the executables
73 | JAVACMD="$JAVA_HOME/jre/sh/java"
74 | else
75 | JAVACMD="$JAVA_HOME/bin/java"
76 | fi
77 | if [ ! -x "$JAVACMD" ] ; then
78 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
79 |
80 | Please set the JAVA_HOME variable in your environment to match the
81 | location of your Java installation."
82 | fi
83 | else
84 | JAVACMD="java"
85 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
86 |
87 | Please set the JAVA_HOME variable in your environment to match the
88 | location of your Java installation."
89 | fi
90 |
91 | # Increase the maximum file descriptors if we can.
92 | if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
93 | MAX_FD_LIMIT=`ulimit -H -n`
94 | if [ $? -eq 0 ] ; then
95 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
96 | MAX_FD="$MAX_FD_LIMIT"
97 | fi
98 | ulimit -n $MAX_FD
99 | if [ $? -ne 0 ] ; then
100 | warn "Could not set maximum file descriptor limit: $MAX_FD"
101 | fi
102 | else
103 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
104 | fi
105 | fi
106 |
107 | # For Darwin, add options to specify how the application appears in the dock
108 | if $darwin; then
109 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
110 | fi
111 |
112 | # For Cygwin, switch paths to Windows format before running java
113 | if $cygwin ; then
114 | APP_HOME=`cygpath --path --mixed "$APP_HOME"`
115 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
116 | JAVACMD=`cygpath --unix "$JAVACMD"`
117 |
118 | # We build the pattern for arguments to be converted via cygpath
119 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
120 | SEP=""
121 | for dir in $ROOTDIRSRAW ; do
122 | ROOTDIRS="$ROOTDIRS$SEP$dir"
123 | SEP="|"
124 | done
125 | OURCYGPATTERN="(^($ROOTDIRS))"
126 | # Add a user-defined pattern to the cygpath arguments
127 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then
128 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
129 | fi
130 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
131 | i=0
132 | for arg in "$@" ; do
133 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
134 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
135 |
136 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
137 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
138 | else
139 | eval `echo args$i`="\"$arg\""
140 | fi
141 | i=$((i+1))
142 | done
143 | case $i in
144 | (0) set -- ;;
145 | (1) set -- "$args0" ;;
146 | (2) set -- "$args0" "$args1" ;;
147 | (3) set -- "$args0" "$args1" "$args2" ;;
148 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;;
149 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
150 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
151 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
152 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
153 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
154 | esac
155 | fi
156 |
157 | # Escape application args
158 | save () {
159 | for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
160 | echo " "
161 | }
162 | APP_ARGS=$(save "$@")
163 |
164 | # Collect all arguments for the java command, following the shell quoting and substitution rules
165 | eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
166 |
167 | # by default we should be in the correct project dir, but when run from Finder on Mac, the cwd is wrong
168 | if [ "$(uname)" = "Darwin" ] && [ "$HOME" = "$PWD" ]; then
169 | cd "$(dirname "$0")"
170 | fi
171 |
172 | exec "$JAVACMD" "$@"
173 |
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @if "%DEBUG%" == "" @echo off
2 | @rem ##########################################################################
3 | @rem
4 | @rem Gradle startup script for Windows
5 | @rem
6 | @rem ##########################################################################
7 |
8 | @rem Set local scope for the variables with windows NT shell
9 | if "%OS%"=="Windows_NT" setlocal
10 |
11 | set DIRNAME=%~dp0
12 | if "%DIRNAME%" == "" set DIRNAME=.
13 | set APP_BASE_NAME=%~n0
14 | set APP_HOME=%DIRNAME%
15 |
16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
17 | set DEFAULT_JVM_OPTS=
18 |
19 | @rem Find java.exe
20 | if defined JAVA_HOME goto findJavaFromJavaHome
21 |
22 | set JAVA_EXE=java.exe
23 | %JAVA_EXE% -version >NUL 2>&1
24 | if "%ERRORLEVEL%" == "0" goto init
25 |
26 | echo.
27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
28 | echo.
29 | echo Please set the JAVA_HOME variable in your environment to match the
30 | echo location of your Java installation.
31 |
32 | goto fail
33 |
34 | :findJavaFromJavaHome
35 | set JAVA_HOME=%JAVA_HOME:"=%
36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
37 |
38 | if exist "%JAVA_EXE%" goto init
39 |
40 | echo.
41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
42 | echo.
43 | echo Please set the JAVA_HOME variable in your environment to match the
44 | echo location of your Java installation.
45 |
46 | goto fail
47 |
48 | :init
49 | @rem Get command-line arguments, handling Windows variants
50 |
51 | if not "%OS%" == "Windows_NT" goto win9xME_args
52 |
53 | :win9xME_args
54 | @rem Slurp the command line arguments.
55 | set CMD_LINE_ARGS=
56 | set _SKIP=2
57 |
58 | :win9xME_args_slurp
59 | if "x%~1" == "x" goto execute
60 |
61 | set CMD_LINE_ARGS=%*
62 |
63 | :execute
64 | @rem Setup the command line
65 |
66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
67 |
68 | @rem Execute Gradle
69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS%
70 |
71 | :end
72 | @rem End local scope for the variables with windows NT shell
73 | if "%ERRORLEVEL%"=="0" goto mainEnd
74 |
75 | :fail
76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
77 | rem the _cmd.exe /c_ return code!
78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
79 | exit /b 1
80 |
81 | :mainEnd
82 | if "%OS%"=="Windows_NT" endlocal
83 |
84 | :omega
85 |
--------------------------------------------------------------------------------
/images/install1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HoseaDev/Fast-Generate-MVP-Template/61c420acf59ada8282a129444acedaf99f61c55f/images/install1.png
--------------------------------------------------------------------------------
/images/mvp.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HoseaDev/Fast-Generate-MVP-Template/61c420acf59ada8282a129444acedaf99f61c55f/images/mvp.gif
--------------------------------------------------------------------------------
/images/settings.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HoseaDev/Fast-Generate-MVP-Template/61c420acf59ada8282a129444acedaf99f61c55f/images/settings.png
--------------------------------------------------------------------------------
/images/settings1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HoseaDev/Fast-Generate-MVP-Template/61c420acf59ada8282a129444acedaf99f61c55f/images/settings1.png
--------------------------------------------------------------------------------
/images/use1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HoseaDev/Fast-Generate-MVP-Template/61c420acf59ada8282a129444acedaf99f61c55f/images/use1.png
--------------------------------------------------------------------------------
/images/use2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HoseaDev/Fast-Generate-MVP-Template/61c420acf59ada8282a129444acedaf99f61c55f/images/use2.png
--------------------------------------------------------------------------------
/images/use3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HoseaDev/Fast-Generate-MVP-Template/61c420acf59ada8282a129444acedaf99f61c55f/images/use3.png
--------------------------------------------------------------------------------
/images/use4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/HoseaDev/Fast-Generate-MVP-Template/61c420acf59ada8282a129444acedaf99f61c55f/images/use4.png
--------------------------------------------------------------------------------
/settings.gradle:
--------------------------------------------------------------------------------
1 | rootProject.name = 'mvpaotucodeplus'
2 |
3 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/mvpautocodeplus/Utils.java:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus;
2 |
3 | /**
4 | * Created by XQ Yang on 2018/6/25 18:14.
5 | * Description :
6 | */
7 |
8 | public class Utils {
9 | public Utils() {
10 | }
11 |
12 | public static boolean isEmpty(CharSequence s) {
13 | if (s == null) {
14 | return true;
15 | } else {
16 | return s.length() == 0;
17 | }
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/mvpautocodeplus/ui/ConfigForm.form:
--------------------------------------------------------------------------------
1 |
2 |
309 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/mvpautocodeplus/ui/ConfigForm.java:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.ui;
2 |
3 | import com.intellij.ui.components.labels.LinkLabel;
4 | import com.intellij.uiDesigner.core.GridConstraints;
5 | import com.intellij.uiDesigner.core.GridLayoutManager;
6 | import com.intellij.uiDesigner.core.Spacer;
7 | import java.awt.Color;
8 | import java.awt.Dimension;
9 | import java.awt.Insets;
10 | import javax.swing.BorderFactory;
11 | import javax.swing.ButtonGroup;
12 | import javax.swing.JButton;
13 | import javax.swing.JComponent;
14 | import javax.swing.JLabel;
15 | import javax.swing.JPanel;
16 | import javax.swing.JRadioButton;
17 | import javax.swing.JTextField;
18 |
19 | /**
20 | * Created by XQ Yang on 2018/6/25 14:19.
21 | * Description :
22 | */
23 |
24 | public class ConfigForm {
25 |
26 | public JPanel mPanel;
27 | public JTextField tv_v_name;
28 | public JTextField tv_p_name;
29 | public JTextField tv_m_name;
30 | public JTextField tv_model_impl;
31 | public JTextField tv_presenter_impl;
32 | public JTextField tv_view_activity;
33 | public JTextField tv_view_fragment;
34 | public JButton btn_view_select;
35 | public JButton btn_view_a_select;
36 | public JButton btn_view_f_select;
37 | public JButton btn_p_select;
38 | public JButton btn_pi_select;
39 | public JButton btn_m_select;
40 | public JButton btn_mi_select;
41 | public JTextField et_comment_author;
42 | public LinkLabel lk_look_detail;
43 | public JRadioButton mGlobalRadioButton;
44 | public JRadioButton mCurrentProjectRadioButton;
45 |
46 | private void createUIComponents() {
47 | }
48 |
49 | {
50 | // GUI initializer generated by IntelliJ IDEA GUI Designer
51 | // >>> IMPORTANT!! <<<
52 | // DO NOT EDIT OR ADD ANY CODE HERE!
53 | $$$setupUI$$$();
54 | }
55 |
56 | /**
57 | * Method generated by IntelliJ IDEA GUI Designer
58 | * >>> IMPORTANT!! <<<
59 | * DO NOT edit this method OR call it in your code!
60 | *
61 | * @noinspection ALL
62 | */
63 | private void $$$setupUI$$$() {
64 | mPanel = new JPanel();
65 | mPanel.setLayout(new GridLayoutManager(12, 8, new Insets(0, 0, 0, 0), -1, -1));
66 | mPanel.setMinimumSize(new Dimension(-1, -1));
67 | mPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.createLineBorder(Color.black), "MvpAutoCodePlus"));
68 | final JLabel label1 = new JLabel();
69 | label1.setText("请输入完整的类名,支持M,V,P这样的泛型指定. 比如: com.longforus.IPresenter,生成后将被替换为生成的接口类型.");
70 | mPanel.add(label1,
71 | new GridConstraints(0, 0, 1, 5, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null,
72 | null, 0, false));
73 | final Spacer spacer1 = new Spacer();
74 | mPanel.add(spacer1,
75 | new GridConstraints(0, 7, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
76 | final Spacer spacer2 = new Spacer();
77 | mPanel.add(spacer2,
78 | new GridConstraints(11, 1, 1, 5, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
79 | final JLabel label2 = new JLabel();
80 | label2.setMinimumSize(new Dimension(-1, -1));
81 | label2.setText("Super IView Name: ");
82 | label2.setToolTipText("");
83 | mPanel.add(label2,
84 | new GridConstraints(3, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
85 | new Dimension(186, 17), null, 0, false));
86 | tv_v_name = new JTextField();
87 | tv_v_name.setToolTipText("要生成的IView接口的父接口");
88 | mPanel.add(tv_v_name,
89 | new GridConstraints(3, 2, 1, 4, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
90 | null, new Dimension(150, -1), null, 0, false));
91 | btn_view_select = new JButton();
92 | btn_view_select.setText("...");
93 | mPanel.add(btn_view_select, new GridConstraints(3, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
94 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
95 | final JLabel label3 = new JLabel();
96 | label3.setText("Base View Activity:");
97 | label3.setToolTipText("");
98 | mPanel.add(label3,
99 | new GridConstraints(4, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
100 | new Dimension(186, 17), null, 0, false));
101 | tv_view_activity = new JTextField();
102 | tv_view_activity.setToolTipText("View用Activity实现的父类");
103 | mPanel.add(tv_view_activity,
104 | new GridConstraints(4, 2, 1, 4, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
105 | null, new Dimension(250, -1), null, 0, false));
106 | btn_view_a_select = new JButton();
107 | btn_view_a_select.setText("...");
108 | mPanel.add(btn_view_a_select, new GridConstraints(4, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
109 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
110 | final JLabel label4 = new JLabel();
111 | label4.setText("Base View Fragment:");
112 | label4.setToolTipText("");
113 | mPanel.add(label4,
114 | new GridConstraints(5, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
115 | new Dimension(186, 17), null, 0, false));
116 | tv_view_fragment = new JTextField();
117 | tv_view_fragment.setToolTipText("View用Fragment实现的父类");
118 | mPanel.add(tv_view_fragment,
119 | new GridConstraints(5, 2, 1, 4, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
120 | null, new Dimension(250, -1), null, 0, false));
121 | btn_view_f_select = new JButton();
122 | btn_view_f_select.setText("...");
123 | mPanel.add(btn_view_f_select, new GridConstraints(5, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
124 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
125 | final JLabel label5 = new JLabel();
126 | label5.setText("Super IPresenter Name: ");
127 | label5.setToolTipText("");
128 | mPanel.add(label5,
129 | new GridConstraints(6, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
130 | new Dimension(186, 17), null, 0, false));
131 | tv_p_name = new JTextField();
132 | tv_p_name.setToolTipText("要生成的IPresenter接口的父接口");
133 | mPanel.add(tv_p_name,
134 | new GridConstraints(6, 2, 1, 4, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
135 | null, new Dimension(150, -1), null, 0, false));
136 | btn_p_select = new JButton();
137 | btn_p_select.setText("...");
138 | mPanel.add(btn_p_select, new GridConstraints(6, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
139 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
140 | final JLabel label6 = new JLabel();
141 | label6.setText("Base Presenter Impl:");
142 | label6.setToolTipText("");
143 | label6.putClientProperty("html.disable", Boolean.FALSE);
144 | mPanel.add(label6,
145 | new GridConstraints(7, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
146 | new Dimension(186, 17), null, 0, false));
147 | tv_presenter_impl = new JTextField();
148 | tv_presenter_impl.setToolTipText("Presenter实现类的父类");
149 | mPanel.add(tv_presenter_impl,
150 | new GridConstraints(7, 2, 1, 4, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
151 | null, new Dimension(150, -1), null, 0, false));
152 | btn_pi_select = new JButton();
153 | btn_pi_select.setText("...");
154 | mPanel.add(btn_pi_select, new GridConstraints(7, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
155 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
156 | final JLabel label7 = new JLabel();
157 | label7.setText("Super IModel Name: ");
158 | label7.setToolTipText("");
159 | mPanel.add(label7,
160 | new GridConstraints(8, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
161 | new Dimension(186, 17), null, 0, false));
162 | tv_m_name = new JTextField();
163 | tv_m_name.setToolTipText("要生成的IModel接口的父接口");
164 | mPanel.add(tv_m_name,
165 | new GridConstraints(8, 2, 1, 4, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
166 | null, new Dimension(150, -1), null, 0, false));
167 | btn_m_select = new JButton();
168 | btn_m_select.setText("...");
169 | mPanel.add(btn_m_select, new GridConstraints(8, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
170 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
171 | final JLabel label8 = new JLabel();
172 | label8.setText("Base Model Impl:");
173 | label8.setToolTipText("");
174 | mPanel.add(label8,
175 | new GridConstraints(9, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
176 | new Dimension(186, 17), null, 0, false));
177 | tv_model_impl = new JTextField();
178 | tv_model_impl.setToolTipText("IModel实现类的父类");
179 | mPanel.add(tv_model_impl,
180 | new GridConstraints(9, 2, 1, 4, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
181 | null, new Dimension(150, -1), null, 0, false));
182 | btn_mi_select = new JButton();
183 | btn_mi_select.setText("...");
184 | mPanel.add(btn_mi_select, new GridConstraints(9, 6, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
185 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
186 | final JLabel label9 = new JLabel();
187 | label9.setText("Comment author:");
188 | label9.setToolTipText("");
189 | mPanel.add(label9,
190 | new GridConstraints(10, 0, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null,
191 | new Dimension(186, 17), null, 0, false));
192 | et_comment_author = new JTextField();
193 | et_comment_author.setToolTipText("生成注释中的作者名字");
194 | mPanel.add(et_comment_author,
195 | new GridConstraints(10, 2, 1, 4, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
196 | null, new Dimension(150, -1), null, 0, false));
197 | final JLabel label10 = new JLabel();
198 | label10.setText(" 实现类支持指定多个,用 ; 隔开. 如果需要泛型限定,选择Class后需要手动添加.");
199 | mPanel.add(label10,
200 | new GridConstraints(1, 2, 1, 2, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null,
201 | null, 0, false));
202 | lk_look_detail = new LinkLabel();
203 | lk_look_detail.setText("查看详细用法");
204 | mPanel.add(lk_look_detail,
205 | new GridConstraints(1, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
206 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
207 | final JLabel label11 = new JLabel();
208 | label11.setText("Settings Mode:");
209 | mPanel.add(label11,
210 | new GridConstraints(2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null,
211 | null, 0, false));
212 | mGlobalRadioButton = new JRadioButton();
213 | mGlobalRadioButton.setSelected(true);
214 | mGlobalRadioButton.setText("Global");
215 | mPanel.add(mGlobalRadioButton,
216 | new GridConstraints(2, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
217 | GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
218 | mCurrentProjectRadioButton = new JRadioButton();
219 | mCurrentProjectRadioButton.setText("Current Project");
220 | mPanel.add(mCurrentProjectRadioButton,
221 | new GridConstraints(2, 3, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
222 | GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
223 | ButtonGroup buttonGroup;
224 | buttonGroup = new ButtonGroup();
225 | buttonGroup.add(mGlobalRadioButton);
226 | buttonGroup.add(mCurrentProjectRadioButton);
227 | }
228 |
229 | /** @noinspection ALL */
230 | public JComponent $$$getRootComponent$$$() {
231 | return mPanel;
232 | }
233 | }
234 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/mvpautocodeplus/ui/EnterKeywordDialog.form:
--------------------------------------------------------------------------------
1 |
2 |
266 |
--------------------------------------------------------------------------------
/src/main/java/com/longforus/mvpautocodeplus/ui/EnterKeywordDialog.java:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.ui;
2 |
3 | import com.intellij.ide.util.PropertiesComponent;
4 | import com.intellij.openapi.project.Project;
5 | import com.intellij.openapi.ui.Messages;
6 | import com.intellij.ui.MutableCollectionComboBoxModel;
7 | import com.intellij.uiDesigner.core.GridConstraints;
8 | import com.intellij.uiDesigner.core.GridLayoutManager;
9 | import com.intellij.uiDesigner.core.Spacer;
10 | import com.longforus.mvpautocodeplus.ConsKt;
11 | import com.longforus.mvpautocodeplus.Utils;
12 | import com.longforus.mvpautocodeplus.config.ItemConfigBean;
13 | import java.awt.Dimension;
14 | import java.awt.GridBagConstraints;
15 | import java.awt.GridBagLayout;
16 | import java.awt.Insets;
17 | import java.awt.Toolkit;
18 | import java.awt.event.ItemEvent;
19 | import java.awt.event.KeyEvent;
20 | import java.awt.event.WindowAdapter;
21 | import java.awt.event.WindowEvent;
22 | import java.util.Arrays;
23 | import javax.swing.BorderFactory;
24 | import javax.swing.ButtonGroup;
25 | import javax.swing.JButton;
26 | import javax.swing.JCheckBox;
27 | import javax.swing.JComboBox;
28 | import javax.swing.JComponent;
29 | import javax.swing.JDialog;
30 | import javax.swing.JLabel;
31 | import javax.swing.JPanel;
32 | import javax.swing.JRadioButton;
33 | import javax.swing.JTextField;
34 | import javax.swing.KeyStroke;
35 | import org.apache.http.util.TextUtils;
36 |
37 | public class EnterKeywordDialog extends JDialog {
38 | private static final String NAME_CHECK_STR = "[a-zA-Z]+[0-9a-zA-Z_]";
39 | private final Project mProject;
40 | private JPanel contentPane;
41 | private JButton buttonOK;
42 | private JButton buttonCancel;
43 | private JTextField et_name;
44 | private JRadioButton mJavaRadioButton;
45 | private JRadioButton mKotlinRadioButton;
46 | private JRadioButton mActivityRadioButton;
47 | private JRadioButton mFragmentRadioButton;
48 | private JCheckBox mViewCheckBox;
49 | private JCheckBox mPresenterCheckBox;
50 | private JCheckBox mModelCheckBox;
51 | private JComboBox cob_v;
52 | private JComboBox cob_p;
53 | private JComboBox cob_m;
54 | private JRadioButton mGlobalRadioButton;
55 | private JRadioButton mCurrentProjectRadioButton;
56 | private JCheckBox mcbModel;
57 | private OnOkListener onOkListener;
58 | private PropertiesComponent mState;
59 |
60 | {
61 | // GUI initializer generated by IntelliJ IDEA GUI Designer
62 | // >>> IMPORTANT!! <<<
63 | // DO NOT EDIT OR ADD ANY CODE HERE!
64 | $$$setupUI$$$();
65 | }
66 |
67 | private EnterKeywordDialog(Project project) {
68 | mProject = project;
69 | setContentPane(contentPane);
70 | setModal(true);
71 | getRootPane().setDefaultButton(buttonOK);
72 |
73 | buttonOK.addActionListener(e -> onOK());
74 |
75 | buttonCancel.addActionListener(e -> onCancel());
76 |
77 | // call onCancel() when cross is clicked
78 | setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
79 | addWindowListener(new WindowAdapter() {
80 | public void windowClosing(WindowEvent e) {
81 | onCancel();
82 | }
83 | });
84 |
85 | // call onCancel() on ESCAPE
86 | contentPane.registerKeyboardAction(e -> onCancel(), KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
87 |
88 | mGlobalRadioButton.addItemListener(e -> {
89 | if (e.getID() != ItemEvent.ITEM_STATE_CHANGED) {
90 | return;
91 | }
92 | if (mGlobalRadioButton.isSelected()) {
93 | mState = PropertiesComponent.getInstance();
94 | } else {
95 | mState = PropertiesComponent.getInstance(mProject);
96 | }
97 | setSavedSuperClass(this, mState);
98 | });
99 | }
100 |
101 | public static EnterKeywordDialog getDialog(Project project, OnOkListener onOkListener) {
102 | EnterKeywordDialog dialog = new EnterKeywordDialog(project);
103 | Dimension screensize = Toolkit.getDefaultToolkit().getScreenSize();
104 | int x = (int) screensize.getWidth() / 2 - dialog.getPreferredSize().width / 2;
105 | int y = (int) screensize.getHeight() / 2 - dialog.getPreferredSize().height / 2;
106 | dialog.setTitle("MvpAutoCodePlus");
107 | dialog.setLocation(x, y);
108 | dialog.onOkListener = onOkListener;
109 | PropertiesComponent state = PropertiesComponent.getInstance(project);
110 | boolean useProjectConfig = state.getBoolean(ConsKt.USE_PROJECT_CONFIG, false);
111 | if (useProjectConfig) {
112 | dialog.mState = state;
113 | dialog.mCurrentProjectRadioButton.setSelected(true);
114 | } else {
115 | dialog.mState = PropertiesComponent.getInstance();
116 | }
117 | setSavedSuperClass(dialog, dialog.mState);
118 | boolean generateModel = state.getBoolean(ConsKt.GENERATE_MODEL_CONFIG, true);
119 | dialog.mcbModel.setSelected(generateModel);
120 | dialog.pack();
121 | dialog.setVisible(true);
122 | return dialog;
123 | }
124 |
125 | private static void setSavedSuperClass(EnterKeywordDialog dialog, PropertiesComponent state) {
126 | dialog.mActivityRadioButton.addChangeListener(e -> {
127 | if (dialog.mActivityRadioButton.isSelected()) {
128 | setSuperClass(dialog.cob_v, dialog.mState.getValue(ConsKt.SUPER_VIEW_ACTIVITY), dialog.mViewCheckBox, ConsKt.IS_NOT_SET + "," + ConsKt.GOTO_SETTING);
129 | } else {
130 | setSuperClass(dialog.cob_v, dialog.mState.getValue(ConsKt.SUPER_VIEW_FRAGMENT), dialog.mViewCheckBox, ConsKt.IS_NOT_SET + "," + ConsKt.GOTO_SETTING);
131 | }
132 | });
133 | setSuperClass(dialog.cob_v, state.getValue(ConsKt.SUPER_VIEW_ACTIVITY), dialog.mViewCheckBox, ConsKt.IS_NOT_SET + "," + ConsKt.GOTO_SETTING);
134 | setSuperClass(dialog.cob_p, state.getValue(ConsKt.SUPER_PRESENTER_IMPL), null, ConsKt.IS_NOT_SET + "," + ConsKt.NO_SUPER_CLASS);
135 | setSuperClass(dialog.cob_m, state.getValue(ConsKt.SUPER_MODEL_IMPL), null, ConsKt.IS_NOT_SET + "," + ConsKt.NO_SUPER_CLASS);
136 | }
137 |
138 | private static void setSuperClass(JComboBox cob, String value, JCheckBox jcb, String nullShowStr) {
139 | if (TextUtils.isEmpty(value)) {
140 | value = nullShowStr;
141 | if (jcb != null) {
142 | jcb.setSelected(false);
143 | }
144 | } else if (jcb != null) {
145 | jcb.setSelected(true);
146 | }
147 | cob.setModel(new MutableCollectionComboBoxModel(Arrays.asList(value.split(";"))));
148 | cob.setSelectedIndex(0);
149 | }
150 |
151 | private static String getSelectedContent(JComboBox cob) {
152 | Object item = cob.getSelectedItem();
153 | if (item == null) {
154 | return "";
155 | } else {
156 | return (String) item;
157 | }
158 | }
159 |
160 | private void onCancel() {
161 | // add your code here if necessary
162 | dispose();
163 | }
164 |
165 | private boolean checkImplementInValid(JCheckBox cb, JComboBox cob, String item) {
166 | if (cb.isSelected()) {
167 | String value = (String) cob.getSelectedItem();
168 | if (TextUtils.isEmpty(value) || ConsKt.IS_NOT_SET.equals(value)) {
169 | Messages.showErrorDialog(item + " implement is invalid ", "Error");
170 | return true;
171 | }
172 | }
173 | return false;
174 | }
175 |
176 | private void onOK() {
177 | String sv = mState.getValue(ConsKt.SUPER_VIEW);
178 | String sp = mState.getValue(ConsKt.SUPER_PRESENTER);
179 | String sm = mState.getValue(ConsKt.SUPER_MODEL);
180 | if (TextUtils.isEmpty(sm) || TextUtils.isEmpty(sp) || TextUtils.isEmpty(sv)) {
181 | Messages.showErrorDialog("Has Super interface not set," + ConsKt.GOTO_SETTING, "Error");
182 | return;
183 | }
184 | String key = et_name.getText();
185 | if (Utils.isEmpty(key)) {
186 | Messages.showErrorDialog("Name not allow empty!", "Error");
187 | return;
188 | }
189 | if (!key.matches(NAME_CHECK_STR)) {
190 | Messages.showErrorDialog("An illegal name!", "Error");
191 | return;
192 | }
193 | if (checkImplementInValid(mViewCheckBox, cob_v, "View")) {
194 | return;
195 | }
196 | if (checkImplementInValid(mPresenterCheckBox, cob_p, "Presenter")) {
197 | return;
198 | }
199 | if (checkImplementInValid(mModelCheckBox, cob_m, "Model")) {
200 | return;
201 | }
202 | buttonOK.setEnabled(false);
203 | PropertiesComponent instance = PropertiesComponent.getInstance(mProject);
204 | instance.setValue(ConsKt.USE_PROJECT_CONFIG, !mGlobalRadioButton.isSelected());
205 | instance.setValue(ConsKt.GENERATE_MODEL_CONFIG, mcbModel.isSelected(), true);
206 | if (onOkListener != null) {
207 | onOkListener.onOk(new ItemConfigBean(key, mJavaRadioButton.isSelected(), mActivityRadioButton.isSelected(), getSelectedContent(cob_v), getSelectedContent(cob_p),
208 | getSelectedContent(cob_m), mState, mcbModel.isSelected()));
209 | }
210 | dispose();
211 | }
212 |
213 | /**
214 | * Method generated by IntelliJ IDEA GUI Designer
215 | * >>> IMPORTANT!! <<<
216 | * DO NOT edit this method OR call it in your code!
217 | *
218 | * @noinspection ALL
219 | */
220 | private void $$$setupUI$$$() {
221 | contentPane = new JPanel();
222 | contentPane.setLayout(new GridLayoutManager(6, 2, new Insets(10, 10, 10, 10), -1, -1));
223 | contentPane.setMinimumSize(new Dimension(400, 376));
224 | final JPanel panel1 = new JPanel();
225 | panel1.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
226 | contentPane.add(panel1,
227 | new GridConstraints(5, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
228 | 1, null, null, null, 0, false));
229 | final Spacer spacer1 = new Spacer();
230 | panel1.add(spacer1,
231 | new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
232 | final JPanel panel2 = new JPanel();
233 | panel2.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1, true, false));
234 | panel1.add(panel2,
235 | new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
236 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
237 | buttonOK = new JButton();
238 | buttonOK.setText("OK");
239 | panel2.add(buttonOK, new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
240 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
241 | buttonCancel = new JButton();
242 | buttonCancel.setText("Cancel");
243 | panel2.add(buttonCancel, new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL,
244 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
245 | final JPanel panel3 = new JPanel();
246 | panel3.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
247 | contentPane.add(panel3,
248 | new GridConstraints(0, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
249 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
250 | final JLabel label1 = new JLabel();
251 | label1.setText("Enter Name:");
252 | panel3.add(label1,
253 | new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null,
254 | null, 0, false));
255 | et_name = new JTextField();
256 | et_name.setText("");
257 | panel3.add(et_name,
258 | new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED,
259 | null, new Dimension(150, -1), null, 0, false));
260 | final JPanel panel4 = new JPanel();
261 | panel4.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
262 | contentPane.add(panel4,
263 | new GridConstraints(1, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
264 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
265 | panel4.setBorder(BorderFactory.createTitledBorder("Implement code type:"));
266 | mJavaRadioButton = new JRadioButton();
267 | mJavaRadioButton.setSelected(true);
268 | mJavaRadioButton.setText("Java");
269 | panel4.add(mJavaRadioButton,
270 | new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
271 | GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
272 | mKotlinRadioButton = new JRadioButton();
273 | mKotlinRadioButton.setText("Kotlin");
274 | panel4.add(mKotlinRadioButton,
275 | new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
276 | GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
277 | final JPanel panel5 = new JPanel();
278 | panel5.setLayout(new GridBagLayout());
279 | contentPane.add(panel5,
280 | new GridConstraints(3, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
281 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
282 | panel5.setBorder(BorderFactory.createTitledBorder("Generate implement item:"));
283 | mViewCheckBox = new JCheckBox();
284 | mViewCheckBox.setSelected(true);
285 | mViewCheckBox.setText("View");
286 | GridBagConstraints gbc;
287 | gbc = new GridBagConstraints();
288 | gbc.gridx = 0;
289 | gbc.gridy = 1;
290 | gbc.weightx = 1.0;
291 | gbc.weighty = 1.0;
292 | gbc.anchor = GridBagConstraints.WEST;
293 | panel5.add(mViewCheckBox, gbc);
294 | mPresenterCheckBox = new JCheckBox();
295 | mPresenterCheckBox.setSelected(true);
296 | mPresenterCheckBox.setText("Presenter");
297 | gbc = new GridBagConstraints();
298 | gbc.gridx = 0;
299 | gbc.gridy = 2;
300 | gbc.weightx = 1.0;
301 | gbc.weighty = 1.0;
302 | gbc.anchor = GridBagConstraints.WEST;
303 | panel5.add(mPresenterCheckBox, gbc);
304 | mModelCheckBox = new JCheckBox();
305 | mModelCheckBox.setSelected(true);
306 | mModelCheckBox.setText("Model");
307 | gbc = new GridBagConstraints();
308 | gbc.gridx = 0;
309 | gbc.gridy = 3;
310 | gbc.weightx = 1.0;
311 | gbc.weighty = 1.0;
312 | gbc.anchor = GridBagConstraints.WEST;
313 | panel5.add(mModelCheckBox, gbc);
314 | cob_m = new JComboBox();
315 | gbc = new GridBagConstraints();
316 | gbc.gridx = 1;
317 | gbc.gridy = 3;
318 | gbc.gridwidth = 3;
319 | gbc.weightx = 20.0;
320 | gbc.anchor = GridBagConstraints.WEST;
321 | gbc.fill = GridBagConstraints.HORIZONTAL;
322 | panel5.add(cob_m, gbc);
323 | cob_p = new JComboBox();
324 | gbc = new GridBagConstraints();
325 | gbc.gridx = 1;
326 | gbc.gridy = 2;
327 | gbc.gridwidth = 3;
328 | gbc.anchor = GridBagConstraints.WEST;
329 | gbc.fill = GridBagConstraints.HORIZONTAL;
330 | panel5.add(cob_p, gbc);
331 | cob_v = new JComboBox();
332 | gbc = new GridBagConstraints();
333 | gbc.gridx = 1;
334 | gbc.gridy = 1;
335 | gbc.gridwidth = 3;
336 | gbc.anchor = GridBagConstraints.WEST;
337 | gbc.fill = GridBagConstraints.HORIZONTAL;
338 | panel5.add(cob_v, gbc);
339 | final JLabel label2 = new JLabel();
340 | label2.setText("Settings Mode:");
341 | gbc = new GridBagConstraints();
342 | gbc.gridx = 0;
343 | gbc.gridy = 0;
344 | gbc.anchor = GridBagConstraints.WEST;
345 | panel5.add(label2, gbc);
346 | mGlobalRadioButton = new JRadioButton();
347 | mGlobalRadioButton.setSelected(true);
348 | mGlobalRadioButton.setText("Global");
349 | gbc = new GridBagConstraints();
350 | gbc.gridx = 1;
351 | gbc.gridy = 0;
352 | gbc.anchor = GridBagConstraints.WEST;
353 | panel5.add(mGlobalRadioButton, gbc);
354 | mCurrentProjectRadioButton = new JRadioButton();
355 | mCurrentProjectRadioButton.setText("Current Project");
356 | gbc = new GridBagConstraints();
357 | gbc.gridx = 3;
358 | gbc.gridy = 0;
359 | gbc.anchor = GridBagConstraints.WEST;
360 | panel5.add(mCurrentProjectRadioButton, gbc);
361 | final JPanel spacer2 = new JPanel();
362 | gbc = new GridBagConstraints();
363 | gbc.gridx = 2;
364 | gbc.gridy = 0;
365 | gbc.fill = GridBagConstraints.HORIZONTAL;
366 | gbc.ipadx = 100;
367 | panel5.add(spacer2, gbc);
368 | final Spacer spacer3 = new Spacer();
369 | contentPane.add(spacer3,
370 | new GridConstraints(4, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, new Dimension(-1, 50), null,
371 | null, 0, false));
372 | final JPanel panel6 = new JPanel();
373 | panel6.setLayout(new GridLayoutManager(1, 2, new Insets(0, 0, 0, 0), -1, -1));
374 | panel6.setToolTipText("View implement type:");
375 | contentPane.add(panel6,
376 | new GridConstraints(2, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
377 | GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
378 | panel6.setBorder(BorderFactory.createTitledBorder("View implement type:"));
379 | mActivityRadioButton = new JRadioButton();
380 | mActivityRadioButton.setSelected(true);
381 | mActivityRadioButton.setText("Acitivy");
382 | panel6.add(mActivityRadioButton,
383 | new GridConstraints(0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
384 | GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
385 | mFragmentRadioButton = new JRadioButton();
386 | mFragmentRadioButton.setText("Fragment");
387 | panel6.add(mFragmentRadioButton,
388 | new GridConstraints(0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
389 | GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
390 | mcbModel = new JCheckBox();
391 | mcbModel.setSelected(true);
392 | mcbModel.setText("Generate IModel");
393 | contentPane.add(mcbModel,
394 | new GridConstraints(4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW,
395 | GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
396 | ButtonGroup buttonGroup;
397 | buttonGroup = new ButtonGroup();
398 | buttonGroup.add(mJavaRadioButton);
399 | buttonGroup.add(mKotlinRadioButton);
400 | buttonGroup = new ButtonGroup();
401 | buttonGroup.add(mActivityRadioButton);
402 | buttonGroup.add(mFragmentRadioButton);
403 | buttonGroup = new ButtonGroup();
404 | buttonGroup.add(mGlobalRadioButton);
405 | buttonGroup.add(mCurrentProjectRadioButton);
406 | }
407 |
408 | /** @noinspection ALL */
409 | public JComponent $$$getRootComponent$$$() {
410 | return contentPane;
411 | }
412 |
413 | @FunctionalInterface
414 | public interface OnOkListener {
415 | void onOk(ItemConfigBean str);
416 | }
417 | }
418 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/Cons.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus
2 |
3 | /**
4 | * Created by XQ Yang on 2018/6/26 11:14.
5 | * Description : 常量
6 | */
7 |
8 | fun getContractName(name: String) = "I${name}Contract"
9 |
10 | fun getViewInfName(name: String) = "I${name}View"
11 | fun getPresenterInfName(name: String) = "I${name}Presenter"
12 | fun getModelInfName(name: String) = "I${name}Model"
13 |
14 | const val USE_PROJECT_CONFIG = "use_project_config"
15 | const val GENERATE_MODEL_CONFIG = "generate_model_config"
16 | const val GOTO_SETTING = "Please go to File-> Settings -> OtherSettings -> MvpAutoCodePlus set."
17 | const val IS_NOT_SET = "Is not set"
18 | const val NO_SUPER_CLASS = "The implementation class will have no superclass"
19 |
20 | const val CONTRACT = "contract"
21 | const val VIEW = "view"
22 | const val PRESENTER = "presenter"
23 | const val MODEL = "model"
24 |
25 |
26 | const val SUPER_VIEW = "super_view"
27 | const val SUPER_PRESENTER = "super_presenter"
28 | const val SUPER_MODEL = "super_model"
29 | const val SUPER_VIEW_ACTIVITY = "super_view_activity"
30 | const val SUPER_VIEW_FRAGMENT = "super_view_fragment"
31 | const val SUPER_PRESENTER_IMPL = "super_presenter_impl"
32 | const val SUPER_MODEL_IMPL = "super_model_impl"
33 | const val COMMENT_AUTHOR = "comment_author"
34 |
35 |
36 | const val CONTRACT_TP_NAME_JAVA = "JavaMvpAutoCodePlusContract"
37 | const val CONTRACT_TP_NAME_KOTLIN = "KotlinMvpAutoCodePlusContract"
38 | const val CONTRACT_TP_NO_MODEL_NAME_JAVA = "JavaMvpAutoCodePlusContractNoModel"
39 | const val CONTRACT_TP_NO_MODEL_NAME_KOTLIN = "KotlinMvpAutoCodePlusContractNoModel"
40 | const val VIEW_IMPL_TP_ACTIVITY_JAVA = "JavaMvpAutoCodePlusViewActivityImpl"
41 | const val VIEW_IMPL_TP_ACTIVITY_KOTLIN = "KotlinMvpAutoCodePlusViewActivityImpl"
42 | const val VIEW_IMPL_TP_FRAGMENT_JAVA = "JavaMvpAutoCodePlusViewFragmentImpl"
43 | const val VIEW_IMPL_TP_FRAGMENT_KOTLIN = "KotlinMvpAutoCodePlusViewFragmentImpl"
44 | const val PRESENTER_IMPL_TP_JAVA = "JavaMvpAutoCodePlusPresenterImpl"
45 | const val PRESENTER_IMPL_TP_KOTLIN = "KotlinMvpAutoCodePlusPresenterImpl"
46 | const val MODEL_IMPL_TP_JAVA = "JavaMvpAutoCodePlusModelImpl"
47 | const val MODEL_IMPL_TP_KOTLIN = "KotlinMvpAutoCodePlusModelImpl"
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/Extfun.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus
2 |
3 | /**
4 | * Created by XQ Yang on 2018/6/25 19:17.
5 | * Description :
6 | */
7 |
8 | fun MutableSet.eAdd(vararg e: E): Set {
9 | if (e.size > 1) {
10 | this.addAll(e)
11 | } else if (e.isNotEmpty()) {
12 | this.add(e[0])
13 | }
14 | return this
15 | }
16 |
17 | fun String.lastDotContent() = this.substring(this.lastIndexOf(".") + 1, this.length)
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/MainAction.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus
2 |
3 | import com.intellij.featureStatistics.FeatureUsageTracker
4 | import com.intellij.featureStatistics.ProductivityFeatureNames
5 | import com.intellij.ide.actions.CreateFileAction
6 | import com.intellij.ide.util.PropertiesComponent
7 | import com.intellij.openapi.actionSystem.*
8 | import com.intellij.openapi.application.WriteActionAware
9 | import com.intellij.openapi.fileEditor.FileEditorManager
10 | import com.intellij.openapi.fileEditor.TextEditor
11 | import com.intellij.openapi.module.ModuleUtil
12 | import com.intellij.openapi.project.Project
13 | import com.intellij.psi.*
14 | import com.intellij.util.PlatformIcons
15 | import com.longforus.mvpautocodeplus.config.ItemConfigBean
16 | import com.longforus.mvpautocodeplus.maker.*
17 | import com.longforus.mvpautocodeplus.ui.EnterKeywordDialog
18 | import org.jetbrains.android.dom.manifest.Manifest
19 | import org.jetbrains.android.facet.AndroidFacet
20 | import org.jetbrains.android.facet.AndroidRootUtil
21 | import org.jetbrains.android.util.AndroidUtils
22 | import org.jetbrains.kotlin.psi.KtFile
23 | import com.intellij.openapi.application.runWriteAction as runWriteAction1
24 |
25 |
26 | /**
27 | * Created by XQ Yang on 2018/6/25 13:43.
28 | * Description :
29 | */
30 |
31 | open class MainAction : AnAction("Generate MVP Code", "auto make mvp code", PlatformIcons.CLASS_ICON), WriteActionAware {
32 | var project: Project? = null
33 | private lateinit var mSelectedState: PropertiesComponent
34 | var curAppPackage:String? = null
35 |
36 | private fun createFile(enterName: String, templateName: String, dir: PsiDirectory, superImplName: String, contract: PsiFile? = null, fileName: String = enterName): Pair {
38 | var clazz: PsiClass? = null
39 | val template = TemplateMaker.getTemplate(templateName, project!!) ?: return null to null
40 | val liveTemplateDefaultValues = TemplateParamFactory.getParam4TemplateName(templateName, enterName, superImplName, contract, mSelectedState).toMutableMap().also {
41 | it["CUR_APP_PACKAGE"] = curAppPackage
42 | it["ENTER_NAME"] = enterName
43 | }
44 | val psiFile = createFileFromTemplate(fileName, template, dir, null, false, liveTemplateDefaultValues, mSelectedState.getValue(COMMENT_AUTHOR))
45 | if (!templateName.contains("Contract")) {
46 | val openFile = FileEditorManager.getInstance(project!!).openFile(psiFile!!.virtualFile, false)
47 | val textEditor = openFile[0] as TextEditor
48 |
49 | if (psiFile is PsiJavaFile) {
50 | if (psiFile.classes.isEmpty()) {
51 | return psiFile to null
52 | }
53 | clazz = psiFile.classes[0]
54 | } else if (psiFile is KtFile) {
55 | if (psiFile.classes.isEmpty()) {
56 | return psiFile to null
57 | }
58 | clazz = psiFile.classes[0]
59 | }
60 | FeatureUsageTracker.getInstance().triggerFeatureUsed(ProductivityFeatureNames.CODEASSISTS_OVERRIDE_IMPLEMENT)
61 | overrideOrImplementMethods(project!!, textEditor.editor, clazz!!, true)
62 | }
63 | return psiFile to clazz
64 | }
65 |
66 | override fun actionPerformed(e: AnActionEvent) {
67 | val dataContext = e.dataContext
68 | val view = LangDataKeys.IDE_VIEW.getData(dataContext) ?: return
69 | project = CommonDataKeys.PROJECT.getData(dataContext)
70 | val dir = view.orChooseDirectory
71 |
72 | if (dir == null || project == null) return
73 | // var state: PropertiesComponent = PropertiesComponent.getInstance(project)
74 | // if (!state.getBoolean(USE_PROJECT_CONFIG,false)) {
75 | // state = PropertiesComponent.getInstance()
76 | // }
77 | // if (state.getValue(SUPER_VIEW).isNullOrEmpty()) {
78 | // Messages.showErrorDialog("Super IView Interface name is null ! $GOTO_SETTING", "Error")
79 | // return
80 | // }
81 |
82 | //NewAndroidComponentDialog
83 |
84 | EnterKeywordDialog.getDialog(project) {
85 | mSelectedState = it.state
86 | val module = ModuleUtil.findModuleForFile(dir.virtualFile, project!!)
87 | val facet = AndroidFacet.getInstance(module!!)
88 | if (facet != null) {
89 | AndroidRootUtil.getManifestFileForCompiler(facet)?.let {
90 | AndroidUtils.loadDomElement(facet.module, it, Manifest::class.java)?.let {
91 | curAppPackage = it.getPackage()?.value
92 | }
93 | }
94 | }
95 | runWriteAction1 {
96 | if (it.isJava) {
97 | doJavaCreate(it, dir, facet)
98 | } else {
99 | doKtCreate(it, dir, facet)
100 | }
101 | }
102 | }
103 | }
104 |
105 | private fun doKtCreate(it: ItemConfigBean, dir: PsiDirectory, facet: AndroidFacet?) {
106 | val contractK = createFile(it.name, if (it.generateModel) CONTRACT_TP_NAME_KOTLIN else CONTRACT_TP_NO_MODEL_NAME_KOTLIN, getSubDir(dir, CONTRACT), "",
107 | fileName = getContractName(it
108 | .name))
109 |
110 | if (it.vImpl.isNotEmpty() && !it.vImpl.startsWith(IS_NOT_SET)) {
111 | val sdV = getSubDir(dir, VIEW)
112 | if (it.isActivity) {
113 | val activityKt = createFile(it.name, VIEW_IMPL_TP_ACTIVITY_KOTLIN, sdV, it.vImpl, contractK.first, "${it.name}Activity")
114 | ComponentRegister.registerActivity(project!!,activityKt.second, JavaDirectoryService.getInstance().getPackage(dir), facet!!, "")
115 | doCreateLayoutFile(it,activityKt.second, project!!, facet, false)
116 | } else {
117 | val fragmentKt = createFile(it.name, VIEW_IMPL_TP_FRAGMENT_KOTLIN, sdV, it.vImpl, contractK.first, "${it.name}Fragment")
118 | doCreateLayoutFile(it,fragmentKt.second, project!!, facet!!, false,false)
119 | }
120 | }
121 | if (it.pImpl.isNotEmpty()) {
122 | val sdP = getSubDir(dir, PRESENTER)
123 | createFile(it.name, PRESENTER_IMPL_TP_KOTLIN, sdP, it.pImpl, contractK.first, "${it.name}${TemplateParamFactory.getPresenterOrViewModel(it.pImpl)}")
124 | }
125 | if (it.mImpl.isNotEmpty() && it.generateModel) {
126 | val sdM = getSubDir(dir, MODEL)
127 | createFile(it.name, MODEL_IMPL_TP_KOTLIN, sdM, it.mImpl, contractK.first, "${it.name}Model")
128 | }
129 | }
130 |
131 | private fun doJavaCreate(it: ItemConfigBean, dir: PsiDirectory, facet: AndroidFacet?) {
132 | val contractJ = createFile(it.name, if (it.generateModel) CONTRACT_TP_NAME_JAVA else CONTRACT_TP_NO_MODEL_NAME_JAVA, getSubDir(dir, CONTRACT),
133 | "")
134 | if (it.vImpl.isNotEmpty() && !it.vImpl.startsWith(IS_NOT_SET)) {
135 | val sdV = getSubDir(dir, VIEW)
136 | if (it.isActivity) {
137 | val activityJava = createFile(it.name, VIEW_IMPL_TP_ACTIVITY_JAVA, sdV, it.vImpl, contractJ.first)
138 | ComponentRegister.registerActivity(project!!,activityJava.second, JavaDirectoryService.getInstance().getPackage(dir), facet!!, "")
139 | doCreateLayoutFile(it,activityJava.second, project!!, facet, true)
140 | } else {
141 | val fragmentJava = createFile(it.name, VIEW_IMPL_TP_FRAGMENT_JAVA, sdV, it.vImpl, contractJ.first)
142 | doCreateLayoutFile(it,fragmentJava.second, project!!, facet!!, true,false)
143 | }
144 | }
145 | if (it.pImpl.isNotEmpty()) {
146 | val sdP = getSubDir(dir, PRESENTER)
147 | createFile(it.name, PRESENTER_IMPL_TP_JAVA, sdP, it.pImpl, contractJ.first)
148 | }
149 | if (it.mImpl.isNotEmpty() && it.generateModel) {
150 | val sdM = getSubDir(dir, MODEL)
151 | createFile(it.name, MODEL_IMPL_TP_JAVA, sdM, it.mImpl, contractJ.first)
152 | }
153 | }
154 |
155 |
156 | private fun getSubDir(dir: PsiDirectory, dirName: String): PsiDirectory {
157 | return if (dir.name == CONTRACT) {
158 | if (dirName == CONTRACT) {
159 | dir
160 | } else {
161 | CreateFileAction.findOrCreateSubdirectory(dir.parentDirectory!!, dirName)
162 | }
163 | } else {
164 | CreateFileAction.findOrCreateSubdirectory(dir, dirName)
165 | }
166 | }
167 |
168 |
169 | override fun update(e: AnActionEvent) {
170 | super.update(e)
171 | val dataContext = e.dataContext
172 | val presentation = e.presentation
173 |
174 | val enabled = isAvailable(dataContext)
175 |
176 | presentation.isVisible = enabled
177 | presentation.isEnabled = enabled
178 | }
179 |
180 | private fun isAvailable(dataContext: DataContext): Boolean {
181 | val project = CommonDataKeys.PROJECT.getData(dataContext)
182 | val view = LangDataKeys.IDE_VIEW.getData(dataContext)
183 | return project != null && view != null && view.directories.isNotEmpty()
184 | }
185 |
186 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/TemplateCons.java:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus;
2 |
3 | /**
4 | * Created by XQ Yang on 2018/6/28 11:02.
5 | * @describe 模版常量
6 | */
7 |
8 | public interface TemplateCons {
9 |
10 | String CONTRACT_TP_CONTENT_JAVA =
11 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n" + "\n" + "import ${V};\n" + "import ${P};\n" + "import ${M};\n" + "/**\n" + " * @describe \n" +
12 | " * @author ${USER}\n" + " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" +
13 | "public interface I${NAME}Contract {\n" + " interface IView extends ${VN}${VG}{}\n" + " interface I${P_OR_M} extends ${PN}${PG}{}\n" +
14 | " interface IModel extends ${MN}${MG}{}\n" + "}\n";
15 | String CONTRACT_TP_CONTENT_NO_MODEL_JAVA =
16 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n" + "\n" + "import ${V};\n" + "import ${P};\n" + "/**\n" + " * @describe \n" + " * @author ${USER}\n" +
17 | " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + "public interface I${NAME}Contract {\n" +
18 | " interface IView extends ${VN}${VG}{}\n" + " interface I${P_OR_M} extends ${PN}${PG}{}\n" + "}\n";
19 |
20 | String CONTRACT_TP_CONTENT_KOTLIN =
21 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME}#end\n" + "\n" + "import ${V}\n" + "import ${P}\n" + "import ${M}\n" + "/**\n" + " * @describe \n" +
22 | " * @author ${USER}\n" + " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + "interface ${NAME} {\n" +
23 | " interface IView : ${VN}${VG}{}\n" + " interface I${P_OR_M} : ${PN}${PG}{}\n" + " interface IModel : ${MN}${MG}{}\n" + "}\n";
24 |
25 | //${ENTER_NAME}
26 | String CONTRACT_TP_CONTENT_NO_MODEL_KOTLIN =
27 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME}#end\n" + "\n" + "import ${V}\n" + "import ${P}\n" + "/**\n" + " * @describe \n" + " * @author ${USER}\n" +
28 | " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" + "interface ${NAME} {\n" +
29 | " interface IView : ${VN}${VG}{}\n" + " interface I${P_OR_M} : ${PN}${PG}{}\n" + "}\n";
30 | //${ENTER_NAME}
31 |
32 | String COMMON_IMPL_TP_CONTENT_JAVA =
33 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME};#end\n" + "\n" + "import ${CONTRACT};\n" + "import ${CUR_APP_PACKAGE}.R;\n" + "#if (${IMPL} != \"\")import ${IMPL};#end\n" + "\n" + "\n" + "/**\n" +
34 | " * @describe \n" + " * @author ${USER}\n" + " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" +
35 | "public class ${NAME}${IMPL_TYPE} #if(${IMPL}!=\"\") extends ${IMPL}${VG}#end implements I${NAME}Contract.I${TYPE} {\n" + "\n" + "}\n" + "\n";
36 |
37 |
38 | String COMMON_IMPL_TP_CONTENT_KOTLIN =
39 | "#if (${PACKAGE_NAME} != \"\")package ${PACKAGE_NAME}#end\n" + "\n" + "import ${CONTRACT}\n" + "import ${CUR_APP_PACKAGE}.R\n" + "#if (${IMPL} != \"\")import ${IMPL}#end\n" + "\n" + "/**\n" +
40 | " * @describe \n" + " * @author ${USER}\n" + " * @date ${DATE} ${TIME}\n" + " * \t\t\t\t\t\t\t\t - generate by MvpAutoCodePlus plugin.\n" + " */\n" + "\n" +
41 | "class ${NAME}${IMPL_TYPE} :#if (${IMPL_NP} != \"\") ${IMPL_NP}${VG}(),#end ${CONTRACT_NP}.I${TYPE} {\n" + "\n" + "}\n" + "\n";
42 | }
43 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/config/ConfigComponent.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.config
2 |
3 | import com.intellij.ide.BrowserUtil
4 | import com.intellij.ide.util.PropertiesComponent
5 | import com.intellij.ide.util.TreeClassChooserFactory
6 | import com.intellij.openapi.options.SearchableConfigurable
7 | import com.intellij.openapi.project.Project
8 | import com.intellij.openapi.project.ProjectManager
9 | import com.longforus.mvpautocodeplus.*
10 | import com.longforus.mvpautocodeplus.ui.ConfigForm
11 | import java.awt.event.ItemEvent
12 | import javax.swing.JButton
13 | import javax.swing.JComponent
14 | import javax.swing.JTextField
15 |
16 | /**
17 | * Created by XQ Yang on 2018/6/25 14:12.
18 | * Description : 配置界面
19 | */
20 | class ConfigComponent : SearchableConfigurable {
21 |
22 |
23 | override fun getId(): String {
24 | return displayName
25 | }
26 |
27 | private val mCp: ConfigForm by lazy { ConfigForm() }
28 | lateinit var state: PropertiesComponent
29 |
30 | private val mProject: Project by lazy {
31 | if (ProjectManager.getInstance().openProjects.isNotEmpty()) {
32 | ProjectManager.getInstance().openProjects[0]
33 | } else {
34 | ProjectManager.getInstance().defaultProject
35 | }
36 | }
37 | private val classChooserFactory by lazy { TreeClassChooserFactory.getInstance(mProject) }
38 |
39 | override fun isModified(): Boolean {
40 | return mCp.tv_v_name.text != state.getValue(SUPER_VIEW) ||
41 | mCp.tv_p_name.text != state.getValue(SUPER_PRESENTER) ||
42 | mCp.tv_m_name.text != state.getValue(SUPER_MODEL) ||
43 | mCp.tv_model_impl.text != state.getValue(SUPER_MODEL_IMPL) ||
44 | mCp.tv_presenter_impl.text != state.getValue(SUPER_PRESENTER_IMPL) ||
45 | mCp.tv_view_fragment.text != state.getValue(SUPER_VIEW_FRAGMENT) ||
46 | mCp.tv_view_activity.text != state.getValue(SUPER_VIEW_ACTIVITY) ||
47 | mCp.et_comment_author.text != state.getValue(COMMENT_AUTHOR)
48 | }
49 |
50 | override fun getDisplayName(): String {
51 | return "MvpAutoCodePlus"
52 | }
53 |
54 | override fun apply() {
55 | state.setValue(SUPER_VIEW, mCp.tv_v_name.text)
56 | state.setValue(SUPER_PRESENTER, mCp.tv_p_name.text)
57 | state.setValue(SUPER_MODEL, mCp.tv_m_name.text)
58 | state.setValue(SUPER_VIEW_ACTIVITY, mCp.tv_view_activity.text)
59 | state.setValue(SUPER_VIEW_FRAGMENT, mCp.tv_view_fragment.text)
60 | state.setValue(SUPER_PRESENTER_IMPL, mCp.tv_presenter_impl.text)
61 | state.setValue(SUPER_MODEL_IMPL, mCp.tv_model_impl.text)
62 | state.setValue(COMMENT_AUTHOR, mCp.et_comment_author.text)
63 | }
64 |
65 |
66 | override fun createComponent(): JComponent? {
67 | state = PropertiesComponent.getInstance(mProject)
68 | if (state.getBoolean(USE_PROJECT_CONFIG, false)) {
69 | mCp.mCurrentProjectRadioButton.isSelected = true
70 | } else {
71 | state = PropertiesComponent.getInstance()
72 | }
73 | loadValues()
74 | mCp.mGlobalRadioButton.addItemListener {
75 | if (it.id != ItemEvent.ITEM_STATE_CHANGED) {
76 | return@addItemListener
77 | }
78 | state = if (mCp.mGlobalRadioButton.isSelected) {
79 | PropertiesComponent.getInstance()
80 | } else {
81 | PropertiesComponent.getInstance(mProject)
82 | }
83 | loadValues()
84 | }
85 | mCp.lk_look_detail.setListener({ _, _ ->
86 | BrowserUtil.browse("https://github.com/longforus/MvpAutoCodePlus/blob/master/README.md")
87 | }, "https://github.com/longforus")
88 | return mCp.mPanel
89 | }
90 |
91 | private fun loadValues() {
92 | mCp.tv_v_name.text = state.getValue(SUPER_VIEW)
93 | setClassChooser(mCp.btn_view_select, "Select Super View Interface", mCp.tv_v_name)
94 | mCp.tv_p_name.text = state.getValue(SUPER_PRESENTER)
95 | setClassChooser(mCp.btn_p_select, "Select Super Presenter Interface", mCp.tv_p_name)
96 | mCp.tv_m_name.text = state.getValue(SUPER_MODEL)
97 | setClassChooser(mCp.btn_m_select, "Select Super Model Interface", mCp.tv_m_name)
98 | mCp.tv_view_activity.text = state.getValue(SUPER_VIEW_ACTIVITY)
99 | setClassChooser(mCp.btn_view_a_select, "Select View extends super Activity", mCp.tv_view_activity, true)
100 | mCp.tv_view_fragment.text = state.getValue(SUPER_VIEW_FRAGMENT)
101 | setClassChooser(mCp.btn_view_f_select, "Select View extends super Fragment", mCp.tv_view_fragment, true)
102 | mCp.tv_presenter_impl.text = state.getValue(SUPER_PRESENTER_IMPL)
103 | setClassChooser(mCp.btn_pi_select, "Select Presenter extends super Class", mCp.tv_presenter_impl, true)
104 | mCp.tv_model_impl.text = state.getValue(SUPER_MODEL_IMPL)
105 | setClassChooser(mCp.btn_mi_select, "Select Model extends super Class", mCp.tv_model_impl, true)
106 | mCp.et_comment_author.text = state.getValue(COMMENT_AUTHOR)
107 | }
108 |
109 | private fun setClassChooser(jButton: JButton?, title: String, tv: JTextField?, append: Boolean = false) {
110 | if (jButton?.actionListeners?.isNotEmpty() == true) {
111 | return
112 | }
113 | jButton?.addActionListener {
114 | val projectScopeChooser = classChooserFactory.createProjectScopeChooser(title)
115 | projectScopeChooser.showDialog()
116 | if (projectScopeChooser.selected != null) {
117 | if (append && !tv?.text.isNullOrEmpty()) {
118 | tv?.text = "${tv?.text};${projectScopeChooser.selected.qualifiedName}"
119 | } else {
120 | tv?.text = projectScopeChooser.selected.qualifiedName
121 | }
122 | }
123 | }
124 | }
125 |
126 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/config/ItemConfigBean.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.config
2 |
3 | import com.intellij.ide.util.PropertiesComponent
4 |
5 | /**
6 | * Created by XQ Yang on 2018/6/28 16:20.
7 | * Description :
8 | */
9 | data class ItemConfigBean(val name: String, val isJava: Boolean = true, val isActivity: Boolean = true, val vImpl: String, val pImpl: String, val mImpl: String,
10 | val state: PropertiesComponent, val generateModel: Boolean = true)
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/maker/CodeMaker.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.maker
2 |
3 | import com.intellij.ide.actions.CreateFileAction
4 | import com.intellij.ide.fileTemplates.FileTemplate
5 | import com.intellij.ide.fileTemplates.FileTemplateManager
6 | import com.intellij.ide.fileTemplates.FileTemplateUtil
7 | import com.intellij.ide.fileTemplates.actions.CreateFromTemplateActionBase
8 | import com.intellij.ide.util.PropertiesComponent
9 | import com.intellij.openapi.fileEditor.FileEditorManager
10 | import com.intellij.psi.PsiDirectory
11 | import com.intellij.psi.PsiFile
12 | import com.intellij.psi.SmartPointerManager
13 | import com.intellij.util.IncorrectOperationException
14 | import org.apache.velocity.runtime.parser.ParseException
15 |
16 | /**
17 | * Created by XQ Yang on 2018/6/28 15:34.
18 | * Description : 创建对应的源文件
19 | */
20 |
21 |
22 |
23 |
24 | fun createFileFromTemplate(fileName: String?,
25 | template: FileTemplate,
26 | d: PsiDirectory,
27 | defaultTemplateProperty: String?,
28 | openFile: Boolean,
29 | liveTemplateDefaultValues: Map,
30 | author: String?): PsiFile? {
31 | var name = fileName
32 | var dir = d
33 | if (name != null) {
34 | val mkdirs = CreateFileAction.MkDirs(name, dir)
35 | name = mkdirs.newName
36 | dir = mkdirs.directory
37 | }
38 |
39 | val project = dir.project
40 | try {
41 | val defaultProperties = FileTemplateManager.getInstance(dir.project).defaultProperties
42 | defaultProperties.putAll(liveTemplateDefaultValues)
43 | if (!author.isNullOrEmpty()) {
44 | defaultProperties["USER"] = author
45 | }
46 | val psiFile = FileTemplateUtil.createFromTemplate(template, name, defaultProperties, dir)
47 | .containingFile
48 | val pointer = SmartPointerManager.getInstance(project).createSmartPsiElementPointer(psiFile)
49 |
50 | val virtualFile = psiFile.virtualFile
51 | if (virtualFile != null) {
52 | if (openFile) {
53 | if (template.isLiveTemplateEnabled) {
54 | CreateFromTemplateActionBase.startLiveTemplate(psiFile, liveTemplateDefaultValues)
55 | } else {
56 | FileEditorManager.getInstance(project).openFile(virtualFile, true)
57 | }
58 | }
59 | if (defaultTemplateProperty != null) {
60 | PropertiesComponent.getInstance(project).setValue(defaultTemplateProperty, template.name)
61 | }
62 | return pointer.element
63 | }
64 | } catch (e: ParseException) {
65 | throw IncorrectOperationException("Error parsing Velocity template: " + e.message, e as Throwable)
66 | } catch (e: IncorrectOperationException) {
67 | throw e
68 | } catch (e: Exception) {
69 | e.printStackTrace()
70 | }
71 |
72 | return null
73 | }
74 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/maker/ComponentRegister.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.maker
2 |
3 | import com.intellij.openapi.command.WriteCommandAction
4 | import com.intellij.openapi.project.Project
5 | import com.intellij.openapi.vfs.ReadonlyStatusHandler
6 | import com.intellij.psi.PsiClass
7 | import com.intellij.psi.PsiPackage
8 | import org.jetbrains.android.dom.manifest.Application
9 | import org.jetbrains.android.dom.manifest.ApplicationComponent
10 | import org.jetbrains.android.dom.manifest.Manifest
11 | import org.jetbrains.android.dom.resources.ResourceValue
12 | import org.jetbrains.android.facet.AndroidFacet
13 | import org.jetbrains.android.facet.AndroidRootUtil
14 | import org.jetbrains.android.util.AndroidUtils
15 |
16 | /**
17 | * @describe
18 | * @author longforus
19 | * @date 2020/3/18 15:11
20 | */
21 | object ComponentRegister {
22 |
23 | fun registerActivity(project:Project,aClass: PsiClass?, aPackage: PsiPackage?, facet: AndroidFacet, label: String?) {
24 | val manifestFile = AndroidRootUtil.getPrimaryManifestFile(facet)
25 | if (manifestFile != null && ReadonlyStatusHandler.ensureFilesWritable(facet.module.project, manifestFile)) {
26 | val manifest = AndroidUtils.loadDomElement(facet.module, manifestFile,
27 | Manifest::class.java)
28 | if (manifest != null) {
29 | val packageName = manifest.getPackage().value
30 | if (packageName == null || packageName.isEmpty()) {
31 | manifest.getPackage().value = aPackage?.qualifiedName
32 | }
33 | val application = manifest.application
34 | if (application != null) {
35 | WriteCommandAction.writeCommandAction(project, aClass!!.containingFile).run {
36 | val component = addToManifest( aClass, application)
37 | if (component != null && !label.isNullOrEmpty()) {
38 | component.label.value = ResourceValue.literal(label)
39 | }
40 | }
41 |
42 | }
43 | }
44 | }
45 | }
46 |
47 |
48 | fun addToManifest(aClass: PsiClass, application: Application): ApplicationComponent? {
49 | val activity = application.addActivity()
50 | activity.activityClass.value = aClass
51 | return activity
52 | }
53 |
54 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/maker/FileMaker.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.maker
2 |
3 | import java.text.SimpleDateFormat
4 |
5 |
6 | /**
7 | * Created by XQ Yang on 2018/6/26 13:55.
8 | * Description :
9 | */
10 | @Deprecated("使用模版方式生成更简单")
11 | val mDateFormat = SimpleDateFormat("yyyy-MM-dd HH:mm:ss")
12 |
13 |
14 | /*
15 | fun make(name: String, type: String, dir: PsiDirectory, project: Project?): PsiFile? {
16 | return when (type) {
17 | "1" -> javaNoImpl(name, dir, project)
18 | else -> null
19 | }
20 | }
21 |
22 | fun javaNoImpl(createName: String, dir: PsiDirectory, project: Project?): PsiFile? {
23 | val fileName = "${getContractName(createName)}.java"
24 | val file = dir.findFile(fileName)
25 | if (file != null) {
26 | return null
27 | }
28 | val path = dir.virtualFile.path
29 | val packageName = path.substring(path.indexOf("com"), path.length).replace("/", ".")
30 |
31 | val state = ServiceManager.getService(PersistentState::class.java)
32 | val vClassName = createTypeName(state.getValue(SUPER_VIEW), packageName, createName)
33 | val pClassName = createTypeName(state.getValue(SUPER_PRESENTER), packageName, createName)
34 | val mClassName = createTypeName(state.getValue(SUPER_MODEL), packageName, createName)
35 |
36 | val viewType = TypeSpec.interfaceBuilder("View").addModifiers(Modifier.PUBLIC, Modifier.STATIC)
37 | .addSuperinterface(vClassName).build()
38 | val presenterType = TypeSpec.interfaceBuilder("Presenter").addModifiers(Modifier
39 | .PUBLIC, Modifier.STATIC)
40 | .addSuperinterface(pClassName).build()
41 | val mType = TypeSpec.interfaceBuilder("Model").addModifiers(Modifier.PUBLIC, Modifier.STATIC).addSuperinterface(mClassName).build()
42 | val contract = TypeSpec.interfaceBuilder(getContractName(createName)).addModifiers(Modifier.PUBLIC).addType(viewType).addType(presenterType)
43 | .addType(mType)
44 | .build()
45 | val javaFile = JavaFile.builder(packageName, contract).addFileComment("This class generate by mvpAutoCodePlus . Void Young - " + mDateFormat.format(Date())).build()
46 | val sb = StringBuilder()
47 | javaFile.writeTo(sb)
48 | val result = PsiFileFactory.getInstance(project).createFileFromText(fileName, JavaLanguage.INSTANCE, sb.toString(), true, false, true)
49 | dir.add(result)
50 | return result
51 | }
52 |
53 |
54 | private fun createTypeName(spValue: String?, curPackageName: String, createName: String): TypeName {
55 | if (spValue.isNullOrEmpty()) {
56 | throw IllegalArgumentException("Super Interface name is null !")
57 | }
58 | val indexOf = spValue!!.lastIndexOf(".")
59 | var spName = spValue.substring(indexOf + 1, spValue.length)
60 | var sPPackageName = spValue.substring(0, indexOf)
61 | var typeName = ""
62 | if (spName.contains("<")) {
63 | val endIndex = spName.indexOf("<")
64 | typeName = spName.substring(endIndex + 1, spName.indexOf(">"))
65 | spName = spName.substring(0, endIndex)
66 | }
67 |
68 | var pClassName: TypeName = ClassName.get(sPPackageName, spName)
69 | val typeClassNames = mutableListOf()
70 | if (typeName.isNotEmpty()) {
71 | val types = typeName.split(",")
72 | for (s in types) {
73 | typeClassNames.add(when (s) {
74 | "V" -> ClassName.get(curPackageName, "${getContractName(createName)}.View")
75 | "P" -> ClassName.get(curPackageName, "${getContractName(createName)}.Presenter")
76 | "M" -> ClassName.get(curPackageName, "${getContractName(createName)}.Model")
77 | else -> throw IllegalArgumentException("$s is not support type")
78 | })
79 | }
80 | if (typeClassNames.isNotEmpty()) {
81 | pClassName = ParameterizedTypeName.get(pClassName as ClassName, typeClassNames as List?)
82 | }
83 | }
84 | return pClassName
85 | }
86 | */
87 |
88 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/maker/LayoutCreator.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.maker
2 |
3 | import com.android.resources.ResourceFolderType
4 | import com.android.resources.ResourceType
5 | import com.android.tools.idea.util.dependsOnAndroidx
6 | import com.intellij.ide.fileTemplates.FileTemplate
7 | import com.intellij.ide.fileTemplates.FileTemplateManager
8 | import com.intellij.ide.fileTemplates.FileTemplateUtil
9 | import com.intellij.openapi.application.ApplicationManager
10 | import com.intellij.openapi.command.WriteCommandAction
11 | import com.intellij.openapi.module.ModuleUtilCore
12 | import com.intellij.openapi.project.Project
13 | import com.intellij.openapi.vfs.LocalFileSystem
14 | import com.intellij.psi.*
15 | import com.intellij.psi.codeStyle.CodeStyleManager
16 | import com.intellij.psi.codeStyle.JavaCodeStyleManager
17 | import com.intellij.psi.xml.XmlFile
18 | import com.longforus.mvpautocodeplus.config.ItemConfigBean
19 | import org.jetbrains.android.dom.manifest.Manifest
20 | import org.jetbrains.android.facet.AndroidFacet
21 | import org.jetbrains.android.facet.AndroidRootUtil
22 | import org.jetbrains.android.sdk.AndroidPlatform
23 | import org.jetbrains.android.util.AndroidUtils
24 | import org.jetbrains.annotations.NotNull
25 | import java.util.*
26 |
27 |
28 | /**
29 | * @describe
30 | * @author longforus
31 | * @date 2020/3/18 16:07
32 | */
33 |
34 |
35 |
36 |
37 | @Throws(Exception::class)
38 | fun doCreateLayoutFile(ic: ItemConfigBean,element: PsiClass?, project: Project, facet: AndroidFacet, isJava: Boolean,isActivity:Boolean = true): PsiElement? {
39 | return if (element == null) {
40 | null
41 | } else {
42 | val manifestFile = AndroidRootUtil.getManifestFileForCompiler(facet) ?: return null
43 | val manifest = AndroidUtils.loadDomElement(facet.module, manifestFile,Manifest::class.java)
44 | // val manifest = Manifest.getMainManifest(facet)
45 | val appPackage = manifest?.getPackage()?.value
46 | if (appPackage != null && appPackage.isNotEmpty()) {
47 | ApplicationManager.getApplication().invokeLater {
48 | LocalFileSystem.getInstance().findFileByPath(AndroidRootUtil.getResourceDirPath(facet) ?: "")?.let {
49 | PsiManager.getInstance(project).findDirectory(it)?.let {
50 | createLayoutFileForActivityOrFragment(ic,facet, element, appPackage, it, isJava,isActivity)
51 |
52 | }
53 | }
54 |
55 | }
56 | }
57 | element
58 | }
59 | }
60 |
61 | fun createLayoutFileForActivityOrFragment(ic: ItemConfigBean,facet: AndroidFacet, activityClass: PsiClass, appPackage: String, resDirectory: PsiDirectory, isJava: Boolean,isActivity:Boolean ) {
62 | if (!facet.isDisposed && activityClass.isValid) {
63 | val className = activityClass.name
64 | if (className != null) {
65 | // val layoutFile = CreateResourceFileAction.createFileResource(facet, ResourceFolderType.LAYOUT, "activity_auto", null, null, true, "Create Layout For '$className'",
66 | // resDirectory, null, false)
67 | val nameSb = StringBuilder()
68 | ic.name.forEach {
69 | if (it >= "A"[0] && it <= "Z"[0]) {
70 | nameSb.append("_")
71 | }
72 | nameSb.append(it)
73 | }
74 |
75 | val layoutFileOriginName = if (isActivity) "activity${nameSb.toString().toLowerCase()}" else "frag${nameSb.toString().toLowerCase()}"
76 |
77 | val rootLayoutName = if (facet.module.dependsOnAndroidx()) "androidx.constraintlayout.widget.ConstraintLayout" else "android.support.constraint.ConstraintLayout"
78 |
79 | val layoutFile = createFileResource(
80 | layoutFileOriginName, resDirectory.findSubdirectory("layout")!!,
81 | rootLayoutName,
82 | ResourceFolderType.LAYOUT.getName(), false)
83 |
84 | //生成布局返回代码,暂时无法解决kotlin代码编辑的问题
85 | // val layoutFileName = layoutFile?.name
86 | // val onCreateMethods = activityClass.findMethodsByName("getLayoutId", false)//viewBinding点不好用
87 | // if (onCreateMethods.size != 1) {
88 | // return
89 | // }
90 | // if (activityClass is KtUltraLightClass){
91 | //
92 | // val psiMethod = activityClass.kotlinOrigin.findFunctionByName("getLayoutId") as KtNamedFunction
93 | //
94 | // val fieldName = AndroidResourceUtil.getRJavaFieldName(FileUtil.getNameWithoutExtension(layoutFileName))
95 | // val layoutFieldRef = "$appPackage.R.layout.$fieldName"
96 | //// getKtStatement(psiMethod, layoutFieldRef, false)
97 | //
98 | // }
99 | // val onCreateMethod = onCreateMethods[0]
100 | // val fieldName = AndroidResourceUtil.getRJavaFieldName(FileUtil.getNameWithoutExtension(layoutFileName))
101 | // val layoutFieldRef = "$appPackage.R.layout.$fieldName"
102 | // getKtStatement(onCreateMethod, layoutFieldRef, isJava)
103 | }
104 | }
105 | }
106 |
107 |
108 | @NotNull
109 | @Throws(java.lang.Exception::class)
110 | fun createFileResource(@NotNull fileName: String?, @NotNull resSubdir: PsiDirectory, @NotNull rootTagName: String?, @NotNull resourceType: String?,
111 | valuesResourceFile: Boolean): XmlFile? {
112 | val apiLevel: Int
113 | val template: FileTemplate = FileTemplateManager.getInstance(resSubdir.project).getJ2eeTemplate(org.jetbrains.android.AndroidFileTemplateProvider.LAYOUT_RESOURCE_FILE_TEMPLATE)
114 | val properties = Properties()
115 | if (!valuesResourceFile) {
116 | properties.setProperty("ROOT_TAG", rootTagName)
117 | }
118 | if (ResourceType.LAYOUT.getName().equals(resourceType)) {
119 | val module: com.intellij.openapi.module.Module? = ModuleUtilCore.findModuleForPsiElement(resSubdir)
120 | val platform: AndroidPlatform? = if (module != null) AndroidPlatform.getInstance(module) else null
121 | apiLevel = platform?.apiLevel ?: -1
122 | val value = if (apiLevel == -1 || apiLevel >= 8) "match_parent" else "fill_parent"
123 | properties.setProperty("LAYOUT_WIDTH", value)
124 | properties.setProperty("LAYOUT_HEIGHT", value)
125 | }
126 | val createdElement: PsiElement = FileTemplateUtil.createFromTemplate(template, fileName, properties, resSubdir)
127 | if (createdElement is XmlFile) {
128 | return createdElement
129 | }
130 | throw AssertionError()
131 | }
132 |
133 |
134 |
135 | fun addInflateStatement(body: PsiCodeBlock, layoutFieldRef: String, isJava: Boolean) {
136 | val project = body.project
137 | val statements = body.statements
138 | if (statements.size == 1) {
139 | val statement = statements[0]
140 | WriteCommandAction.writeCommandAction(project, body.containingFile).run {
141 | val newStatement = PsiElementFactory.getInstance(project).createStatementFromText(
142 | "return $layoutFieldRef${if (isJava) ";" else ""}", body)
143 | statement.replace(newStatement)
144 | JavaCodeStyleManager.getInstance(project).shortenClassReferences(body)
145 | CodeStyleManager.getInstance(project).reformat(body)
146 | }
147 | }
148 | }
149 | fun getKtStatement(method: PsiMethod, layoutFieldRef: String, isJava: Boolean) {
150 | val project = method.project
151 | WriteCommandAction.writeCommandAction(project, method.containingFile).run {
152 | val newStatement = PsiElementFactory.getInstance(project).createStatementFromText(
153 | "return $layoutFieldRef${if (isJava) ";" else ""}", method)
154 | method.add(newStatement)
155 | JavaCodeStyleManager.getInstance(project).shortenClassReferences(method)
156 | CodeStyleManager.getInstance(project).reformat(method)
157 | }
158 | }
159 |
160 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/maker/MethodImpl.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.maker
2 |
3 | import com.intellij.codeInsight.generation.GenerateMembersUtil
4 | import com.intellij.codeInsight.generation.OverrideImplementExploreUtil
5 | import com.intellij.codeInsight.generation.OverrideImplementUtil.*
6 | import com.intellij.codeInsight.generation.PsiGenerationInfo
7 | import com.intellij.codeInsight.generation.PsiMethodMember
8 | import com.intellij.openapi.application.ApplicationManager
9 | import com.intellij.openapi.command.WriteCommandAction.writeCommandAction
10 | import com.intellij.openapi.editor.Editor
11 | import com.intellij.openapi.project.Project
12 | import com.intellij.psi.JavaPsiFacade
13 | import com.intellij.psi.PsiClass
14 | import com.intellij.psi.PsiMethod
15 | import com.intellij.psi.PsiModifier
16 | import com.intellij.util.IncorrectOperationException
17 | import com.intellij.util.containers.ContainerUtil
18 | import org.jetbrains.kotlin.asJava.classes.KtLightClass
19 | import org.jetbrains.kotlin.idea.core.overrideImplement.ImplementMembersHandler
20 | import org.jetbrains.kotlin.idea.core.overrideImplement.OverrideImplementMembersHandler
21 |
22 | /**
23 | * Created by XQ Yang on 2018/7/2 15:53.
24 | * Description : 实现抽象方法
25 | */
26 | val implementMembersHandler = ImplementMembersHandler()
27 |
28 |
29 | fun overrideOrImplementMethods(project: Project,
30 | editor: Editor,
31 | aClass: PsiClass,
32 | toImplement: Boolean) {
33 | if (aClass is KtLightClass) {
34 | kotlinDoMultiOverrideImplement(aClass, project, editor)
35 | } else {
36 | javaOverrideOrImplementMethods(project, editor, aClass, toImplement)
37 | }
38 | }
39 |
40 |
41 | fun kotlinDoMultiOverrideImplement(aClass: KtLightClass, project: Project, editor: Editor) {
42 | // val classOrObject = PsiTreeUtil.getParentOfType(aClass, KtClassOrObject::class.java)
43 | // ?: error("Caret should be inside class or object")
44 | val classOrObject = aClass.kotlinOrigin ?: error("Caret should be inside class or object")
45 |
46 |
47 | val chooserObjects = implementMembersHandler.collectMembersToGenerate(
48 | classOrObject).sortedBy { it.descriptor.name.asString() + " in " + it.immediateSuper.containingDeclaration.name.asString() }
49 |
50 | writeCommandAction(project, aClass.containingFile).run {
51 | OverrideImplementMembersHandler.generateMembers(editor, classOrObject, chooserObjects, false)
52 | }
53 | }
54 |
55 |
56 | fun javaOverrideOrImplementMethods(project: Project,
57 | editor: Editor,
58 | aClass: PsiClass,
59 | toImplement: Boolean) {
60 |
61 | ApplicationManager.getApplication().assertReadAccessAllowed()
62 | val candidates = OverrideImplementExploreUtil.getMethodsToOverrideImplement(aClass, toImplement)
63 | val secondary = if (toImplement || aClass.isInterface)
64 | arrayListOf()
65 | else
66 | OverrideImplementExploreUtil.getMethodsToOverrideImplement(aClass, true)
67 |
68 | if (candidates.isEmpty() && secondary.isEmpty()) return
69 |
70 | if (toImplement) {
71 | val iterator = candidates.iterator()
72 | while (iterator.hasNext()) {
73 | val candidate = iterator.next()
74 | val element = candidate.element
75 | if (element is PsiMethod && element.hasModifierProperty(PsiModifier.DEFAULT)) {
76 | iterator.remove()
77 | secondary.add(candidate)
78 | }
79 | }
80 | }
81 |
82 |
83 | val onlyPrimary = ContainerUtil.map2Array(candidates, PsiMethodMember::class.java) { s -> PsiMethodMember(s) }
84 | val allList = ArrayList()
85 | for (member in onlyPrimary) {
86 | allList.add(member)
87 | }
88 | writeCommandAction(project, aClass.containingFile).run {
89 | overrideOrImplementMethodsInRightPlace(editor, aClass, allList, false, true)
90 | }
91 | }
92 |
93 |
94 | fun overrideOrImplementMethodsInRightPlace(editor: Editor,
95 | aClass: PsiClass,
96 | candidates: Collection,
97 | copyJavadoc: Boolean,
98 | insertOverrideWherePossible: Boolean) {
99 | try {
100 | val offset = 0
101 | var brace = aClass.lBrace
102 | if (brace == null) {
103 | val psiClass = JavaPsiFacade.getInstance(aClass.project).elementFactory.createClass("X")
104 | brace = aClass.addRangeAfter(psiClass.lBrace, psiClass.rBrace, aClass.lastChild)
105 | }
106 |
107 | val lbraceOffset = brace!!.textOffset
108 | val resultMembers: MutableList>
109 | if (offset <= lbraceOffset || aClass.isEnum) {
110 | resultMembers = java.util.ArrayList()
111 | for (candidate in candidates) {
112 | val prototypes = overrideOrImplementMethod(aClass, candidate.element, candidate.substitutor, copyJavadoc, insertOverrideWherePossible)
113 | val infos = convert2GenerationInfos(prototypes)
114 | for (info in infos) {
115 | val anchor = getDefaultAnchorToOverrideOrImplement(aClass, candidate.element, candidate.substitutor)
116 | info.insert(aClass, anchor, true)
117 | resultMembers.add(info)
118 | }
119 | }
120 | } else {
121 | val prototypes = overrideOrImplementMethods(aClass, candidates, copyJavadoc, insertOverrideWherePossible)
122 | resultMembers = GenerateMembersUtil.insertMembersAtOffset(aClass, offset, prototypes)
123 | }
124 |
125 | if (resultMembers.isNotEmpty()) {
126 | resultMembers[0].positionCaret(editor, true)
127 | }
128 | } catch (e: IncorrectOperationException) {
129 | e.printStackTrace()
130 | }
131 |
132 | }
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/maker/TemplateMaker.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.maker
2 |
3 | import com.intellij.ide.fileTemplates.FileTemplate
4 | import com.intellij.ide.fileTemplates.FileTemplateManager
5 | import com.intellij.ide.fileTemplates.FileTemplateUtil
6 | import com.intellij.ide.fileTemplates.impl.FileTemplateManagerImpl
7 | import com.intellij.openapi.project.Project
8 | import com.longforus.mvpautocodeplus.*
9 |
10 | /**
11 | * Created by XQ Yang on 2018/6/28 10:46.
12 | * Description : template管理类
13 | */
14 |
15 | object TemplateMaker {
16 |
17 | var tpManager: FileTemplateManagerImpl? = null
18 | val cacheTemplate = HashMap()
19 |
20 |
21 | private fun createContractTemplate(name: String, type: String, content: String) {
22 | val template = FileTemplateUtil.createTemplate(name, type, content,
23 | tpManager!!.getTemplates(FileTemplateManager.DEFAULT_TEMPLATES_CATEGORY))
24 | template.isLiveTemplateEnabled = false
25 | //保存到ide中,这里就不保存了
26 | // tpManager.setTemplates(FileTemplateManager.DEFAULT_TEMPLATES_CATEGORY, listOf(template))
27 | cacheTemplate[name] = template
28 | }
29 |
30 | fun getTemplate(templateName: String, project: Project): FileTemplate? {
31 | if (cacheTemplate.contains(templateName)) {
32 | return cacheTemplate[templateName] as FileTemplate
33 | } else if (tpManager == null) {
34 | tpManager = FileTemplateManagerImpl.getInstanceImpl(project)
35 | }
36 |
37 | when (templateName) {
38 | CONTRACT_TP_NAME_JAVA -> createContractTemplate(templateName, "java", TemplateCons.CONTRACT_TP_CONTENT_JAVA)
39 | CONTRACT_TP_NAME_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.CONTRACT_TP_CONTENT_KOTLIN)
40 | CONTRACT_TP_NO_MODEL_NAME_JAVA -> createContractTemplate(templateName, "java", TemplateCons.CONTRACT_TP_CONTENT_NO_MODEL_JAVA)
41 | CONTRACT_TP_NO_MODEL_NAME_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.CONTRACT_TP_CONTENT_NO_MODEL_KOTLIN)
42 | VIEW_IMPL_TP_ACTIVITY_JAVA -> createContractTemplate(templateName, "java", TemplateCons.COMMON_IMPL_TP_CONTENT_JAVA)
43 | VIEW_IMPL_TP_FRAGMENT_JAVA -> createContractTemplate(templateName, "java", TemplateCons.COMMON_IMPL_TP_CONTENT_JAVA)
44 | PRESENTER_IMPL_TP_JAVA -> createContractTemplate(templateName, "java", TemplateCons.COMMON_IMPL_TP_CONTENT_JAVA)
45 | MODEL_IMPL_TP_JAVA -> createContractTemplate(templateName, "java", TemplateCons.COMMON_IMPL_TP_CONTENT_JAVA)
46 | VIEW_IMPL_TP_ACTIVITY_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.COMMON_IMPL_TP_CONTENT_KOTLIN)
47 | VIEW_IMPL_TP_FRAGMENT_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.COMMON_IMPL_TP_CONTENT_KOTLIN)
48 | PRESENTER_IMPL_TP_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.COMMON_IMPL_TP_CONTENT_KOTLIN)
49 | MODEL_IMPL_TP_KOTLIN -> createContractTemplate(templateName, "kt", TemplateCons.COMMON_IMPL_TP_CONTENT_KOTLIN)
50 | }
51 |
52 | return if (cacheTemplate.containsKey(templateName)) cacheTemplate[templateName] as FileTemplate else null
53 | }
54 |
55 |
56 | }
57 |
58 |
59 |
--------------------------------------------------------------------------------
/src/main/kotlin/com/longforus/mvpautocodeplus/maker/TemplateParamFactory.kt:
--------------------------------------------------------------------------------
1 | package com.longforus.mvpautocodeplus.maker
2 |
3 | import com.intellij.ide.util.PropertiesComponent
4 | import com.intellij.openapi.ui.Messages
5 | import com.intellij.psi.PsiFile
6 | import com.intellij.psi.PsiJavaFile
7 | import com.longforus.mvpautocodeplus.*
8 | import java.util.*
9 |
10 | /**
11 | * Created by XQ Yang on 2018/6/28 14:18.
12 | * Description : template参数工厂
13 | */
14 |
15 | object TemplateParamFactory {
16 |
17 | private var state: PropertiesComponent? = null
18 |
19 | fun getParam4TemplateName(templateName: String, enterName: String, superImplName: String, contract: PsiFile?,
20 | mSelectedState: PropertiesComponent): Map {
21 | this.state = mSelectedState
22 | val liveTemplateParam = HashMap()
23 | when (templateName) {
24 | CONTRACT_TP_NAME_JAVA, CONTRACT_TP_NAME_KOTLIN, CONTRACT_TP_NO_MODEL_NAME_JAVA, CONTRACT_TP_NO_MODEL_NAME_KOTLIN -> {
25 | val (superVNameNoGeneric, superVGenericValue) = getNameAndGenericType(SUPER_VIEW)
26 | val (superPNameNoGeneric, superPGenericValue) = getNameAndGenericType(SUPER_PRESENTER)
27 | val (superMNameNoGeneric, superMGenericValue) = getNameAndGenericType(SUPER_MODEL)
28 | liveTemplateParam["V"] = superVNameNoGeneric
29 | liveTemplateParam["M"] = superMNameNoGeneric
30 | liveTemplateParam["P"] = superPNameNoGeneric
31 | liveTemplateParam["VN"] = superVNameNoGeneric?.substring(superVNameNoGeneric.lastIndexOf('.')+1 until superVNameNoGeneric.length)?: "IView"
32 | liveTemplateParam["MN"] = superMNameNoGeneric?.substring(superMNameNoGeneric.lastIndexOf('.')+1 until superMNameNoGeneric.length)?: "IModel"
33 | liveTemplateParam["PN"] = superPNameNoGeneric?.substring(superPNameNoGeneric.lastIndexOf('.')+1 until superPNameNoGeneric.length)?: "IPresenter"
34 |
35 | liveTemplateParam["P_OR_M"] = getPresenterOrViewModel(liveTemplateParam["PN"])
36 | if (liveTemplateParam["P_OR_M"]=="ViewModel"&&superVGenericValue.contains("Presenter")) {
37 | liveTemplateParam["VG"] = superVGenericValue.replace("Presenter","ViewModel")
38 | }else{
39 | liveTemplateParam["VG"] = superVGenericValue
40 | }
41 | liveTemplateParam["PG"] = superPGenericValue
42 | liveTemplateParam["MG"] = superMGenericValue
43 | }
44 | VIEW_IMPL_TP_ACTIVITY_JAVA, VIEW_IMPL_TP_ACTIVITY_KOTLIN -> {
45 | setCommonParam(enterName, superImplName, contract, liveTemplateParam, templateName)
46 | if (templateName == VIEW_IMPL_TP_ACTIVITY_JAVA) {
47 | liveTemplateParam["IMPL_TYPE"] = "Activity"
48 | }
49 | liveTemplateParam["TYPE"] = "View"
50 | }
51 | VIEW_IMPL_TP_FRAGMENT_JAVA, VIEW_IMPL_TP_FRAGMENT_KOTLIN -> {
52 | setCommonParam(enterName, superImplName, contract, liveTemplateParam, templateName)
53 | if (templateName == VIEW_IMPL_TP_FRAGMENT_JAVA) {
54 | liveTemplateParam["IMPL_TYPE"] = "Fragment"
55 | }
56 | liveTemplateParam["TYPE"] = "View"
57 | }
58 | PRESENTER_IMPL_TP_JAVA, PRESENTER_IMPL_TP_KOTLIN -> {
59 | setCommonParam(enterName, superImplName, contract, liveTemplateParam, templateName)
60 | if (templateName == PRESENTER_IMPL_TP_JAVA) {
61 | liveTemplateParam["IMPL_TYPE"] = getPresenterOrViewModel(liveTemplateParam["IMPL"])
62 | }
63 | liveTemplateParam["TYPE"] = getPresenterOrViewModel(liveTemplateParam["IMPL"])
64 | }
65 | MODEL_IMPL_TP_JAVA, MODEL_IMPL_TP_KOTLIN -> {
66 | setCommonParam(enterName, superImplName, contract, liveTemplateParam, templateName)
67 | if (templateName == MODEL_IMPL_TP_JAVA) {
68 | liveTemplateParam["IMPL_TYPE"] = "Model"
69 | }
70 | liveTemplateParam["TYPE"] = "Model"
71 | }
72 | //
73 | }
74 | return liveTemplateParam
75 | }
76 |
77 | fun getPresenterOrViewModel(superName: String?): String? {
78 | if(superName.isNullOrEmpty()){
79 | return null
80 | }
81 | return if(superName.endsWith("ViewModel")) "ViewModel" else "Presenter"
82 | }
83 |
84 |
85 | private fun setCommonParam(name: String, superImplName: String, contract: PsiFile?,
86 | liveTemplateParam: HashMap,
87 | templateName: String) {
88 | val (noGSuperName, superMGenericValue) = getNameAndGenericType("", false, name, superImplName)
89 | var packageName = ""
90 | if (contract is PsiJavaFile) {
91 | packageName = contract.packageName
92 | } else if (contract is org.jetbrains.kotlin.psi.KtFile) {
93 | packageName = contract.packageFqName.asString()
94 | }
95 |
96 | liveTemplateParam["CONTRACT"] = "$packageName.${getContractName(name)}"
97 | liveTemplateParam["IMPL"] = noGSuperName
98 | liveTemplateParam["VG"] = superMGenericValue
99 |
100 | if (templateName.startsWith("Kotlin")) {
101 | if (noGSuperName.isNullOrEmpty()) {
102 | liveTemplateParam["IMPL_NP"] = ""
103 | } else {
104 | liveTemplateParam["IMPL_NP"] = liveTemplateParam["IMPL"]?.lastDotContent()
105 | }
106 | liveTemplateParam["CONTRACT_NP"] = liveTemplateParam["CONTRACT"]?.lastDotContent()
107 |
108 | }
109 | }
110 |
111 |
112 | fun getNameAndGenericType(type: String, isContract: Boolean = true, enterName: String = "", selectedValue: String = ""): Pair {
113 | if (selectedValue.startsWith(IS_NOT_SET)) {
114 | return "" to ""
115 | }
116 | val setValue = if (selectedValue.isNotEmpty()) selectedValue else state?.getValue(type)
117 | if (setValue.isNullOrEmpty()) {
118 | Messages.showErrorDialog("Super Interface name is null !", "Error")
119 | throw IllegalArgumentException("Super Interface name is null !")
120 | }
121 | val indexOf = setValue.indexOf("<")
122 | var generic = ""
123 | var resultName = setValue
124 | if (indexOf > -1) {
125 | resultName = setValue.substring(0, indexOf)
126 | val g = setValue.substring(indexOf, setValue.length)
127 | val sb = StringBuilder()
128 | g.forEach {
129 | when (it) {
130 | "V"[0] -> sb.append(if (isContract) "View" else "${getContractName(enterName)}.IView")
131 | "P"[0] -> sb.append(if (isContract) "Presenter" else "${getContractName(enterName)}.IPresenter")
132 | "M"[0] -> sb.append(if (isContract) "Model" else "${getContractName(enterName)}.IModel")
133 | else -> sb.append(it)
134 | }
135 | }
136 | generic = sb.toString()
137 | }
138 | return resultName to generic
139 | }
140 |
141 | }
142 |
143 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | com.longforus.mvpautocodeplus
4 | MvpAutoCodePlus
5 | longforus
6 |
7 | MvpAutoCodePlus
9 |
10 |
11 |
12 | Website |
13 | GitHub |
14 | Issues |
15 | Blog
16 |
17 |
18 |
19 | An plugin that automatically generates an MVP template code.
20 |
21 | Features:
22 |
23 | - Automatically generate Contract Interface based on the specified super Interface.
24 | - Automatically generate implements class based on the Contract Interface and specified superclass.Add the default implementation of the abstract method.
25 | - Supports generics(currently only have M,V,P).
26 | - Supports Java and Kotlin.
27 |
28 |
29 |
30 | Send feedback
31 | ]]>
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 | com.intellij.modules.platform
44 | org.jetbrains.kotlin
45 |
47 | com.intellij.java
48 | com.intellij.modules.lang
49 | com.intellij.modules.java
50 | org.jetbrains.android
51 |
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
--------------------------------------------------------------------------------