├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ └── Project.xml ├── libraries │ └── gson.xml ├── markdown-navigator-enh.xml ├── markdown-navigator.xml ├── misc.xml ├── modules.xml ├── uiDesigner.xml └── vcs.xml ├── GoogleLibraryVersionQuerier.iml ├── GoogleLibraryVersionQuerier.zip ├── LICENSE ├── README.md ├── lib └── gson-2.8.5.jar ├── out └── production │ └── GoogleLibraryVersionQuerier │ └── META-INF │ ├── GoogleLibraryVersionQuerier.kotlin_module │ └── plugin.xml ├── previews ├── 1.gif ├── 10.png ├── 2.gif ├── 3.gif ├── 4.gif ├── 5.png ├── 6.png ├── 7.png ├── 8.png └── 9.png ├── resources └── META-INF │ └── plugin.xml └── src └── com └── wuyr └── google_library_query ├── GradleContributor.kt ├── NetworkRequstter.kt ├── QueryAction.kt ├── VersionSelectorDialog.form └── VersionSelectorDialog.java /.gitignore: -------------------------------------------------------------------------------- 1 | # Compiled class file 2 | *.class 3 | 4 | # Log file 5 | *.log 6 | 7 | # BlueJ files 8 | *.ctxt 9 | 10 | # Mobile Tools for Java (J2ME) 11 | .mtj.tmp/ 12 | 13 | # Package Files # 14 | #*.jar 15 | *.war 16 | *.nar 17 | *.ear 18 | #*.zip 19 | *.tar.gz 20 | *.rar 21 | 22 | # virtual machine crash logs, see http://www.java.com/en/download/help/error_hotspot.xml 23 | hs_err_pid* 24 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | -------------------------------------------------------------------------------- /.idea/codeStyles/Project.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | xmlns:android 14 | 15 | ^$ 16 | 17 | 18 | 19 |
20 |
21 | 22 | 23 | 24 | xmlns:.* 25 | 26 | ^$ 27 | 28 | 29 | BY_NAME 30 | 31 |
32 |
33 | 34 | 35 | 36 | .*:id 37 | 38 | http://schemas.android.com/apk/res/android 39 | 40 | 41 | 42 |
43 |
44 | 45 | 46 | 47 | .*:name 48 | 49 | http://schemas.android.com/apk/res/android 50 | 51 | 52 | 53 |
54 |
55 | 56 | 57 | 58 | name 59 | 60 | ^$ 61 | 62 | 63 | 64 |
65 |
66 | 67 | 68 | 69 | style 70 | 71 | ^$ 72 | 73 | 74 | 75 |
76 |
77 | 78 | 79 | 80 | .* 81 | 82 | ^$ 83 | 84 | 85 | BY_NAME 86 | 87 |
88 |
89 | 90 | 91 | 92 | .* 93 | 94 | http://schemas.android.com/apk/res/android 95 | 96 | 97 | ANDROID_ATTRIBUTE_ORDER 98 | 99 |
100 |
101 | 102 | 103 | 104 | .* 105 | 106 | .* 107 | 108 | 109 | BY_NAME 110 | 111 |
112 |
113 |
114 |
115 |
116 |
-------------------------------------------------------------------------------- /.idea/libraries/gson.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /.idea/markdown-navigator-enh.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | -------------------------------------------------------------------------------- /.idea/markdown-navigator.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 29 | 30 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/uiDesigner.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /GoogleLibraryVersionQuerier.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /GoogleLibraryVersionQuerier.zip: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/GoogleLibraryVersionQuerier.zip -------------------------------------------------------------------------------- /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 [yyyy] [name of copyright owner] 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 | ## 一款Android Studio插件,帮助你快速添加依赖库和查询历史版本 2 | >### 终于审核通过啦,现在可以直接在AS里检查更新了~ 3 | ### 特性: 4 | #### 1. 编辑build.gradle时,会有代码提示: 5 | 6 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/1.gif) 7 | 8 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/2.gif) 9 | 10 |
11 | 12 | #### 2. 光标定位到目标类库所在行,右键(快捷键『CTRL ALT Q』)可快速查看和替换某个版本: 13 | 14 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/3.gif) ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/4.gif) 15 | 16 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/5.png) 17 | 18 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/6.png) 19 | 20 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/7.png) 21 | 22 |
23 | 24 | ### 使用技巧: 25 | 3.0版本支持了Maven、Jcenter仓库搜索,如果不加一些条件过滤的话,在编辑gradle文件时的代码提示可能会有很多名字相似的库,像这样: 26 | 27 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/9.png) 28 | 29 | 遇到这种情况可以在前面加group(包名)关键词,格式如下: 30 | 31 | **group关键词(包名)**:**artifact关键词(仓库名)** 32 | 33 | 示例: 34 | 35 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/10.png) 36 | 37 | 可以看到过滤了group之后的搜索结果更精准了。 38 | 39 |
40 | 41 | ### 安装: 42 | **在线安装:** 43 | 44 | *Android Studio -> Settings -> Plugins -> Marketplace*:
搜索:***Google Library Version Querier***即可: 45 | 46 | ![preview](https://github.com/wuyr/GoogleLibraryVersionQuerier/raw/master/previews/8.png) 47 | 48 | **本地安装:** 49 | 50 | 到 [releases](https://github.com/wuyr/GoogleLibraryVersionQuerier/releases) 里下载最新 *GoogleLibraryVersionQuerier.zip* 后拖把它拖进Android Studio中并重启。 51 | 52 |
53 | 54 | ### 数据来源:[wanandroid.com](https://wanandroid.com/maven_pom/index) , [maven.aliyun.com](https://maven.aliyun.com/mvn/view) 55 | ### 感谢[鸿神](https://www.wanandroid.com/)提供技术支持 56 | 57 |
58 | 59 | ### 更新日志: 60 | 61 | - **3.3** 修复兼容性问题,现最低兼容到AndroidStudio3.0;优化体验:右键菜单选项『Query available versions』只在编辑.gradle文件时显示;『Query available versions』的快捷键改为『CTRL ALT Q』,因原来的『ALT Q』与其他快捷键有冲突; 62 | 63 | - **3.2** 优化查询,彻底修复编辑gradle文件卡顿的问题;查询可用版本改为倒序排序;加入监听ESC键关闭版本选择对话框。 64 | 65 | - **3.1** 修复键入任何字符和在任何文件下也会弹提示的Bug,加入限制:只有在.gradle文件中的dependencies作用域内才会搜索仓库。 66 | 67 | - **3.0** 支持Maven、Jcenter仓库搜索,支持所有.gradle文件,英文提示改成中文(想想都是国人用,就不整英文了)。 68 | 69 | - **2.1** 修复请求多次接口Bug。 70 | 71 | - **2.0** 加入编辑build.gradle文件时的代码提示和支持搜索历史版本。 72 | 73 | - **1.0** 完成搜索和替换Google官方依赖库最新版本。 74 | 75 | -------------------------------------------------------------------------------- /lib/gson-2.8.5.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/lib/gson-2.8.5.jar -------------------------------------------------------------------------------- /out/production/GoogleLibraryVersionQuerier/META-INF/GoogleLibraryVersionQuerier.kotlin_module: -------------------------------------------------------------------------------- 1 |  2 | 3 3 | com.wuyr.google_library_queryNetworkRequstterKt -------------------------------------------------------------------------------- /out/production/GoogleLibraryVersionQuerier/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.wuyr.google_library_query 3 | Google Library Version Querier 4 | 3.3 5 | 陈小缘 6 | 7 | A plugin to facilitate adding library dependencies and choice historical versions.

9 |
10 |

Github: github.com/wuyr/GoogleLibraryVersionQuerier

11 |
12 |

Powered by wanandroid.com, maven.aliyun.com

13 | ]]>
14 | 15 |
  • 3.3 Compatibility issues fixes.
  • 17 | 18 |

  • 3.2 Bug fixes.
  • 19 | 20 |

  • 3.1 Bug fixes.
  • 21 | 22 |

  • 3.0 Supported Jcenter libraries search.
  • 23 | 24 |

  • 2.1 Bug fixes.
  • 25 | 26 |

  • 2.0 Add build.gradle dependency code completion and free choice of historical version.
  • 27 | 28 |

  • 1.0 Completed the function of finding and replacing the latest version of Google Library.
  • 29 |
    30 | ]]>
    31 | 32 | 33 | 34 | com.intellij.modules.lang 35 | 36 | 37 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 |
    -------------------------------------------------------------------------------- /previews/1.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/1.gif -------------------------------------------------------------------------------- /previews/10.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/10.png -------------------------------------------------------------------------------- /previews/2.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/2.gif -------------------------------------------------------------------------------- /previews/3.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/3.gif -------------------------------------------------------------------------------- /previews/4.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/4.gif -------------------------------------------------------------------------------- /previews/5.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/5.png -------------------------------------------------------------------------------- /previews/6.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/6.png -------------------------------------------------------------------------------- /previews/7.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/7.png -------------------------------------------------------------------------------- /previews/8.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/8.png -------------------------------------------------------------------------------- /previews/9.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wuyr/GoogleLibraryVersionQuerier/8155580e1335513b6564008fb6484da0539c6e0f/previews/9.png -------------------------------------------------------------------------------- /resources/META-INF/plugin.xml: -------------------------------------------------------------------------------- 1 | 2 | com.wuyr.google_library_query 3 | Google Library Version Querier 4 | 3.3 5 | 陈小缘 6 | 7 | A plugin to facilitate adding library dependencies and choice historical versions.

    9 |
    10 |

    Github: github.com/wuyr/GoogleLibraryVersionQuerier

    11 |
    12 |

    Powered by wanandroid.com, maven.aliyun.com

    13 | ]]>
    14 | 15 |
  • 3.3 Compatibility issues fixes.
  • 17 | 18 |

  • 3.2 Bug fixes.
  • 19 | 20 |

  • 3.1 Bug fixes.
  • 21 | 22 |

  • 3.0 Supported Jcenter libraries search.
  • 23 | 24 |

  • 2.1 Bug fixes.
  • 25 | 26 |

  • 2.0 Add build.gradle dependency code completion and free choice of historical version.
  • 27 | 28 |

  • 1.0 Completed the function of finding and replacing the latest version of Google Library.
  • 29 |
    30 | ]]>
    31 | 32 | 33 | 34 | com.intellij.modules.lang 35 | 36 | 37 | 39 | 40 | 41 | 42 | 44 | 45 | 46 | 47 | 48 | 49 |
    -------------------------------------------------------------------------------- /src/com/wuyr/google_library_query/GradleContributor.kt: -------------------------------------------------------------------------------- 1 | package com.wuyr.google_library_query 2 | 3 | import com.intellij.codeInsight.AutoPopupController 4 | import com.intellij.codeInsight.completion.CompletionContributor 5 | import com.intellij.codeInsight.completion.CompletionInitializationContext 6 | import com.intellij.codeInsight.completion.CompletionParameters 7 | import com.intellij.codeInsight.completion.CompletionResultSet 8 | import com.intellij.codeInsight.lookup.LookupElementBuilder 9 | import com.intellij.openapi.command.WriteCommandAction 10 | import com.intellij.openapi.editor.Editor 11 | import com.intellij.openapi.util.TextRange 12 | import com.intellij.util.PlatformIcons 13 | import java.awt.EventQueue 14 | import java.io.StringReader 15 | import java.util.concurrent.Executors 16 | import java.util.concurrent.Future 17 | 18 | /** 19 | * @author wuyr 20 | * @github https://github.com/wuyr/GoogleLibraryVersionQuerier 21 | * @since 2020-05-05 02:58 22 | */ 23 | class GradleContributor : CompletionContributor() { 24 | 25 | private var needShow = false 26 | private var elementList = ArrayList>() 27 | private val acceptFilesType = arrayOf(".gradle") 28 | private val threadPool = Executors.newSingleThreadExecutor() 29 | private var runningQueryThread: Future<*>? = null 30 | private var lastCurrentLineContent = "" 31 | 32 | override fun beforeCompletion(context: CompletionInitializationContext) { 33 | needShow = acceptFilesType.any { context.file.name.endsWith(it) } 34 | if (needShow) { 35 | needShow = isInDependenciesBlock(context) 36 | } else { 37 | cancelQuery() 38 | } 39 | } 40 | 41 | private fun isInDependenciesBlock(context: CompletionInitializationContext): Boolean { 42 | val lines = StringReader(context.editor.document.text).readLines() 43 | var currentLineNumber = context.editor.run { document.getLineNumber(caretModel.offset) } 44 | var braceStartCount = 0 45 | var braceEndCount = 0 46 | while (currentLineNumber >= 0 && currentLineNumber < lines.size) { 47 | val currentLine = lines[currentLineNumber] 48 | braceStartCount += currentLine.count { it == '{' } 49 | braceEndCount += currentLine.count { it == '}' } 50 | if (currentLine.let { it.contains("dependencies") && it.contains('{') }) { 51 | return braceStartCount - braceEndCount == 1 52 | } 53 | currentLineNumber-- 54 | } 55 | return false 56 | } 57 | 58 | override fun fillCompletionVariants(parameters: CompletionParameters, result: CompletionResultSet) { 59 | if (needShow) { 60 | val lineStartPosition = parameters.editor.caretModel.visualLineStart 61 | val lineEndPosition = parameters.editor.caretModel.visualLineEnd 62 | val currentLineContent = parameters.editor.document.getText(TextRange(lineStartPosition, lineEndPosition)).replace("\n".toRegex(), "").trim() 63 | if (elementList.isNotEmpty()) { 64 | if (currentLineContent.contains(lastCurrentLineContent)) { 65 | elementList.forEach { e -> result.addElement(e.toLookupElement()) } 66 | } else { 67 | cancelQuery() 68 | result.stopHere() 69 | } 70 | elementList.clear() 71 | needShow = false 72 | } else { 73 | if (currentLineContent.length < 4 || currentLineContent == lastCurrentLineContent) { 74 | return 75 | } 76 | lastCurrentLineContent = currentLineContent 77 | startQuery(parameters.editor) 78 | } 79 | } else { 80 | if (elementList.isNotEmpty()) elementList.clear() 81 | } 82 | super.fillCompletionVariants(parameters, result) 83 | } 84 | 85 | private fun startQuery(editor: Editor) { 86 | lastCurrentLineContent.split("\\s+".toRegex()).let { lineContent -> 87 | if (lineContent.isNotEmpty()) { 88 | val keyword = lineContent.run { if (size == 1) first() else last() } 89 | runningQueryThread?.cancel(true) 90 | var task: Future<*>? = null 91 | task = threadPool.submit { 92 | task?.let { task -> 93 | val result = matchingLibraries(keyword) + 94 | matchingLibraries2(if (keyword.contains(":")) keyword else ":$keyword") 95 | if (!task.isCancelled) { 96 | elementList.clear() 97 | elementList.addAll(result) 98 | EventQueue.invokeLater { 99 | editor.project?.let { project -> 100 | AutoPopupController.getInstance(project) 101 | .autoPopupMemberLookup(editor, null) 102 | } 103 | } 104 | runningQueryThread = null 105 | } 106 | } 107 | }.also { runningQueryThread = it } 108 | } 109 | } 110 | } 111 | 112 | private fun cancelQuery() { 113 | runningQueryThread?.let { if (!it.isCancelled && !it.isDone) it.cancel(true) } 114 | elementList.clear() 115 | needShow = false 116 | } 117 | 118 | private fun Pair.toLookupElement() = LookupElementBuilder.create(first).bold() 119 | .withIcon(PlatformIcons.LIBRARY_ICON).withTypeText(second, true).withInsertHandler { context, item -> 120 | val lineStartPosition = context.editor.caretModel.visualLineStart 121 | val lineEndPosition = context.editor.caretModel.visualLineEnd 122 | val currentLineContent = context.editor.document.getText(TextRange(lineStartPosition, lineEndPosition)) 123 | var additionalIndex = 0 124 | run { 125 | currentLineContent.forEachIndexed { index, char -> 126 | if (!char.isWhitespace()) { 127 | additionalIndex = index 128 | return@run 129 | } 130 | } 131 | } 132 | WriteCommandAction.runWriteCommandAction(context.project) { 133 | context.document.replaceString(lineStartPosition + additionalIndex, lineEndPosition - 1, item.lookupString) 134 | } 135 | } 136 | } -------------------------------------------------------------------------------- /src/com/wuyr/google_library_query/NetworkRequstter.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("UNCHECKED_CAST") 2 | 3 | package com.wuyr.google_library_query 4 | 5 | import com.google.gson.Gson 6 | import java.io.ByteArrayOutputStream 7 | import java.io.InputStream 8 | import java.net.SocketTimeoutException 9 | import java.net.URL 10 | import java.net.URLDecoder 11 | import javax.net.ssl.HttpsURLConnection 12 | import javax.swing.DefaultListModel 13 | 14 | /** 15 | * @author wuyr 16 | * @github https://github.com/wuyr/GoogleLibraryVersionQuerier 17 | * @since 2020-05-05 15:02 18 | */ 19 | 20 | const val BASE_URL = "https://wanandroid.com/maven_pom/" 21 | const val BASE_URL2 = "https://maven.aliyun.com/" 22 | 23 | @Throws(java.lang.Exception::class) 24 | fun getAvailableVersions(libraryGroup: String, libraryName: String) = search("$libraryGroup:$libraryName") { dataList -> 25 | dataList.find { it["groupName"] == libraryGroup }?.run { 26 | (this["artifactMap"] as? Map)?.run { 27 | (this[libraryName] as? List>)?.map { 28 | it["version"].toString() 29 | } 30 | } 31 | } 32 | } 33 | 34 | @Throws(java.lang.Exception::class) 35 | fun getAvailableVersions2(libraryGroup: String, libraryName: String) = 36 | getSearchAvailableVersionsUrl(libraryGroup, libraryName).request { result -> 37 | result.filter { it["nodeType"] == "FOLDER" }.map { 38 | (it["nodeName"] as String).run { 39 | (if (contains('%')) { 40 | try { 41 | URLDecoder.decode(this, "utf-8") 42 | } catch (e: Exception) { 43 | this 44 | } 45 | } else this).run { substring(0, lastIndex) } 46 | } 47 | } 48 | } 49 | 50 | fun matchingLibraries(keyword: String) = ArrayList>().apply { 51 | runSafely { 52 | search(keyword) { dataList -> 53 | dataList.map { 54 | (it["artifactMap"] as? Map>>)?.values?.map { e -> 55 | e.last().run { 56 | this["content"].toString() to this["group"].toString() 57 | } 58 | } 59 | }.forEach { it?.let { addAll(it) } } 60 | } 61 | } 62 | } 63 | 64 | @Throws(java.lang.Exception::class) 65 | fun matchingLibraries2(keyword: String) = ArrayList>().apply { 66 | runSafely { 67 | keyword.split(":").let { libraryInfo -> 68 | if (libraryInfo.size > 1) { 69 | val libraryGroup = libraryInfo.libraryGroup 70 | val libraryName = libraryInfo.libraryName 71 | if (libraryGroup.length >= 5 || libraryName.length >= 5) { 72 | getSearchLibrariesUrl(libraryGroup, libraryName).request { result -> 73 | result.filter { 74 | (it["packaging"] == "pom").also { hit -> 75 | if (hit) { 76 | it["content"] = "${it["groupId"]}:${it["artifactId"]}" 77 | } 78 | } 79 | }.groupBy { it["content"] }.forEach { 80 | if (it.value.isNotEmpty()) { 81 | it.value.first().let { item -> 82 | add("implementation '${item["content"]}:${item["version"]}'" to item["groupId"].toString()) 83 | } 84 | } 85 | } 86 | } 87 | } 88 | } 89 | } 90 | } 91 | } 92 | 93 | val List.libraryGroup 94 | get() = when { 95 | size > 2 && this[0].isEmpty() -> this[1] 96 | this[0].isEmpty() -> "*" 97 | else -> "*${this[0]}*" 98 | }.run { if (isEmpty()) "*" else this } 99 | 100 | val List.libraryName 101 | get() = when { 102 | this.size > 3 && this[3].isEmpty() -> this[2] 103 | size > 2 && this[2].isEmpty() -> this[1] 104 | size > 2 && this[0].isEmpty() -> if (this[2].isEmpty()) "*" else "*${this[2]}*" 105 | else -> if (this[1].isEmpty()) "*" else "*${this[1]}*" 106 | }.run { if (isEmpty()) "*" else this } 107 | 108 | fun getSearchLibrariesUrl(libraryGroup: String, libraryName: String) = 109 | BASE_URL2 + "artifact/aliyunMaven/searchArtifactByGav?_input_charset=utf-8&groupId=$libraryGroup&repoId=jcenter&artifactId=$libraryName&version=*" 110 | 111 | fun getSearchAvailableVersionsUrl(libraryGroup: String, libraryName: String) = 112 | BASE_URL2 + "browse/tree?_input_charset=utf-8&repoId=jcenter&path=${libraryGroup.replace('.', '/')}/$libraryName/" 113 | 114 | @Throws(java.lang.Exception::class) 115 | inline fun search(keyword: String, block: (List>) -> O): O? = 116 | (BASE_URL + "search/json?k=$keyword").getAPIResponse(1)?.let { json -> 117 | ((Gson().fromJson(json, Map::class.java)["data"]) as? List>)?.run { 118 | block(this) 119 | } 120 | } 121 | 122 | @Throws(java.lang.Exception::class) 123 | inline fun String.request(block: (List>) -> O): O? = getAPIResponse(1)?.let { json -> 124 | (Gson().fromJson(json, Map::class.java) as? Map)?.run { 125 | if (this["successful"] == true) { 126 | block(this["object"] as List>) 127 | } else null 128 | } 129 | } 130 | 131 | @Throws(java.lang.Exception::class) 132 | fun String.getAPIResponse(retryCount: Int): String? { 133 | var currentRetryCount = 0 134 | var exception: Exception? = null 135 | while (currentRetryCount <= retryCount) { 136 | try { 137 | (URL(this).openConnection() as HttpsURLConnection).run { 138 | connectTimeout = 5000 139 | readTimeout = 5000 140 | if (responseCode == 200) { 141 | return inputStream.use { 142 | it.readBytes().toString(Charsets.UTF_8) 143 | } 144 | } else { 145 | currentRetryCount++ 146 | } 147 | } 148 | } catch (e: Exception) { 149 | exception = e 150 | if (e is SocketTimeoutException) { 151 | currentRetryCount++ 152 | } else throw e 153 | } 154 | } 155 | exception?.let { throw exception } ?: return null 156 | } 157 | 158 | private fun InputStream.readBytes(): ByteArray { 159 | val buffer = ByteArrayOutputStream(maxOf(DEFAULT_BUFFER_SIZE, this.available())) 160 | copyTo(buffer) 161 | return buffer.toByteArray() 162 | } 163 | 164 | inline fun T.runSafely(block: (T) -> R) = try { 165 | block(this) 166 | } catch (e: Exception) { 167 | e.printStackTrace() 168 | null 169 | } 170 | 171 | fun main() { 172 | val libraryGroup = "org.jsoup" 173 | val libraryName = "jsoup" 174 | println("json: " + getAvailableVersions(libraryGroup, libraryName)) 175 | println("json: " + getAvailableVersions2(libraryGroup, libraryName)) 176 | println("matchingLibraries: " + matchingLibraries2(":com.squareup.okhttp3:okhttp:")) 177 | VersionSelectorDialog.show(DefaultListModel().apply { 178 | getAvailableVersions2(libraryGroup, libraryName)?.forEach { 179 | addElement(it) 180 | } 181 | }) { 182 | println(it) 183 | } 184 | } -------------------------------------------------------------------------------- /src/com/wuyr/google_library_query/QueryAction.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("UNCHECKED_CAST") 2 | 3 | package com.wuyr.google_library_query 4 | 5 | import com.intellij.openapi.actionSystem.AnAction 6 | import com.intellij.openapi.actionSystem.AnActionEvent 7 | import com.intellij.openapi.actionSystem.CommonDataKeys 8 | import com.intellij.openapi.command.WriteCommandAction 9 | import com.intellij.openapi.ui.Messages 10 | import com.intellij.openapi.util.TextRange 11 | import java.awt.EventQueue 12 | import java.io.PrintWriter 13 | import java.io.StringWriter 14 | import javax.swing.DefaultListModel 15 | import kotlin.concurrent.thread 16 | 17 | 18 | /** 19 | * @author wuyr 20 | * @github https://github.com/wuyr/GoogleLibraryVersionQuerier 21 | * @since 2020-05-04 23:13 22 | */ 23 | @Suppress("ConstantConditionIf") 24 | class QueryAction : AnAction() { 25 | 26 | //版本降序 27 | private val versionComparator = Comparator { v1, v2 -> 28 | //对比索引记录 29 | var v1CompareCursor = 0 30 | var v2CompareCursor = 0 31 | val digitRange = '0'..'9' 32 | while (v1CompareCursor < v1.length && v2CompareCursor < v2.length) { 33 | //数字结束索引 34 | var v1DigitSegmentEndIndex = v1CompareCursor 35 | for (index in v1CompareCursor until v1.length) { 36 | if (v1[index] !in digitRange) break 37 | v1DigitSegmentEndIndex++ 38 | } 39 | var v2DigitSegmentEndIndex = v2CompareCursor 40 | for (index in v2CompareCursor until v2.length) { 41 | if (v2[index] !in digitRange) break 42 | v2DigitSegmentEndIndex++ 43 | } 44 | if (v1DigitSegmentEndIndex > v1CompareCursor && v2DigitSegmentEndIndex > v2CompareCursor) { 45 | //数字长度 46 | val v1DigitSegmentCount = v1DigitSegmentEndIndex - v1CompareCursor 47 | val v2DigitSegmentCount = v2DigitSegmentEndIndex - v2CompareCursor 48 | if (v1DigitSegmentCount != v2DigitSegmentCount) 49 | //长度不相等 50 | return@Comparator v2DigitSegmentCount - v1DigitSegmentCount 51 | 52 | repeat(v1DigitSegmentCount) { index -> 53 | if (v1[v1CompareCursor + index] != v2[v2CompareCursor + index]) 54 | //数字不相等 55 | return@Comparator v2[v2CompareCursor + index] - v1[v1CompareCursor + index] 56 | } 57 | v1CompareCursor = v1DigitSegmentEndIndex 58 | v2CompareCursor = v2DigitSegmentEndIndex 59 | } else { 60 | //其中一方无数字 61 | if (v1[v1CompareCursor] != v2[v2CompareCursor]) 62 | return@Comparator v2[v2CompareCursor] - v1[v1CompareCursor] 63 | v1CompareCursor++ 64 | v2CompareCursor++ 65 | } 66 | } 67 | //部分内容完全相同 68 | v2.length - v1.length 69 | } 70 | 71 | private val acceptFilesType = arrayOf(".gradle") 72 | 73 | override fun update(event: AnActionEvent) { 74 | acceptFilesType.any { event.getData(CommonDataKeys.PSI_FILE)?.name?.endsWith(it) ?: false }.let { enable -> 75 | event.presentation.run { 76 | isEnabled = enable 77 | isVisible = enable 78 | } 79 | } 80 | super.update(event) 81 | } 82 | 83 | override fun actionPerformed(event: AnActionEvent) { 84 | thread { 85 | event.getData(CommonDataKeys.EDITOR)?.let { editor -> 86 | val lineStartPosition = editor.caretModel.visualLineStart 87 | val lineEndPosition = editor.caretModel.visualLineEnd 88 | val currentLineContent = editor.document.getText(TextRange(lineStartPosition, lineEndPosition)) 89 | 90 | val semicolon = ":" 91 | if (!currentLineContent.contains(semicolon)) { 92 | showLibraryInfoNotFoundDialog() 93 | return@thread 94 | } 95 | val singleQuotation = "'" 96 | val doubleQuotation = "\"" 97 | 98 | val isSingleQuotation = currentLineContent.contains(singleQuotation) 99 | val quotation = if (isSingleQuotation) singleQuotation else doubleQuotation 100 | 101 | val libraryStartIndex = currentLineContent.indexOf(quotation) 102 | val libraryEndIndex = currentLineContent.lastIndexOf(quotation) 103 | 104 | if (libraryStartIndex < 0 || libraryEndIndex < libraryStartIndex) { 105 | showLibraryInfoNotFoundDialog() 106 | return@thread 107 | } 108 | val libraryInfo = currentLineContent.substring(libraryStartIndex + 1, libraryEndIndex).split(semicolon).toTypedArray() 109 | val libraryGroup = libraryInfo[0] 110 | val libraryName = libraryInfo[1] 111 | 112 | try { 113 | val versionList = getAvailableVersions(libraryGroup, libraryName).run { 114 | if (isNullOrEmpty()) { 115 | getAvailableVersions2(libraryGroup, libraryName) 116 | } else this 117 | }?.sortedWith(versionComparator) 118 | 119 | versionList?.let { 120 | if (it.isEmpty()) { 121 | showLibraryNotFoundDialog() 122 | } else { 123 | VersionSelectorDialog.show(DefaultListModel().apply { it.forEach { e -> addElement(e) } }) { selectedVersion -> 124 | val oldVersionStart = currentLineContent.lastIndexOf(semicolon) 125 | val oldVersionEnd = currentLineContent.lastIndexOf(if (isSingleQuotation) singleQuotation else doubleQuotation) 126 | val oldVersionString = currentLineContent.substring(oldVersionStart, oldVersionEnd) 127 | val newLineContent = currentLineContent.replace(oldVersionString, semicolon + selectedVersion) 128 | 129 | WriteCommandAction.runWriteCommandAction(event.project) { 130 | editor.document.replaceString(lineStartPosition, lineEndPosition, newLineContent) 131 | } 132 | } 133 | } 134 | } ?: showLibraryNotFoundDialog() 135 | } catch (e: Exception) { 136 | showErrorDialog(e) 137 | } 138 | } 139 | } 140 | } 141 | 142 | private fun showErrorDialog(e: Exception) = EventQueue.invokeAndWait { 143 | Messages.showErrorDialog(StringWriter().use { sw -> 144 | PrintWriter(sw).use { pw -> 145 | pw.println("查找依赖库历史版本时出错!") 146 | pw.println("若不能通过以下log分析到具体原因(如出现UnknownHostException、SocketTimeoutException等Exception,请检查网络是否正常)\n" + 147 | "请复制以下log到 https://github.com/wuyr/GoogleLibraryVersionQuerier 上提issue:\n") 148 | e.printStackTrace(pw) 149 | } 150 | sw.toString() 151 | }.toString(), "出错了") 152 | } 153 | 154 | private fun showLibraryNotFoundDialog() = EventQueue.invokeAndWait { 155 | Messages.showErrorDialog("请检查关键词是否正确,以及确保该依赖库已发布到Google、Maven、Jcenter仓库上!", "找不到该依赖库") 156 | } 157 | 158 | private fun showLibraryInfoNotFoundDialog() = EventQueue.invokeAndWait { 159 | Messages.showErrorDialog("请将光标定位到目标依赖库所在行!", "找不到有效信息") 160 | } 161 | 162 | } -------------------------------------------------------------------------------- /src/com/wuyr/google_library_query/VersionSelectorDialog.form: -------------------------------------------------------------------------------- 1 | 2 |
    3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 |
    64 | -------------------------------------------------------------------------------- /src/com/wuyr/google_library_query/VersionSelectorDialog.java: -------------------------------------------------------------------------------- 1 | package com.wuyr.google_library_query; 2 | 3 | import javax.swing.*; 4 | import java.awt.*; 5 | import java.awt.event.KeyEvent; 6 | import java.awt.event.WindowAdapter; 7 | import java.awt.event.WindowEvent; 8 | 9 | import static javax.swing.JComponent.WHEN_IN_FOCUSED_WINDOW; 10 | 11 | /** 12 | * @author wuyr 13 | * @github https://github.com/wuyr/GoogleLibraryVersionQuerier 14 | * @since 2020-05-05 19:34 15 | */ 16 | public class VersionSelectorDialog extends JDialog { 17 | private JPanel contentPane; 18 | private JButton buttonCancel; 19 | private JList list; 20 | 21 | public VersionSelectorDialog(DefaultListModel dataList, OnSelectedListener onSelectedListener) { 22 | setContentPane(contentPane); 23 | setModal(true); 24 | getRootPane().setDefaultButton(buttonCancel); 25 | 26 | list.setModel(dataList); 27 | list.addListSelectionListener(listSelectionEvent -> { 28 | if (!listSelectionEvent.getValueIsAdjusting()) { 29 | onSelectedListener.onItemSelected(list.getSelectedValue()); 30 | dispose(); 31 | } 32 | }); 33 | 34 | buttonCancel.addActionListener(e -> dispose()); 35 | 36 | setDefaultCloseOperation(DO_NOTHING_ON_CLOSE); 37 | addWindowListener(new WindowAdapter() { 38 | public void windowClosing(WindowEvent e) { 39 | dispose(); 40 | } 41 | }); 42 | 43 | rootPane.registerKeyboardAction(actionEvent -> dispose(), 44 | KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), WHEN_IN_FOCUSED_WINDOW); 45 | } 46 | 47 | public static void show(DefaultListModel dataList, OnSelectedListener onSelectedListener) { 48 | EventQueue.invokeLater(() -> { 49 | VersionSelectorDialog dialog = new VersionSelectorDialog(dataList, onSelectedListener); 50 | dialog.pack(); 51 | final Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); 52 | final int x = (screenSize.width - dialog.getWidth()) / 2; 53 | final int y = (screenSize.height - dialog.getHeight()) / 2; 54 | dialog.setLocation(x, y); 55 | dialog.setVisible(true); 56 | }); 57 | } 58 | 59 | public interface OnSelectedListener { 60 | void onItemSelected(String item); 61 | } 62 | 63 | } 64 | --------------------------------------------------------------------------------