├── .idea
├── .gitignore
├── vcs.xml
├── kotlinc.xml
├── misc.xml
├── gradle.xml
└── uiDesigner.xml
├── Zip
└── Dimens-Generating-3.1.0.zip
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── settings.gradle.kts
├── gradle.properties
├── src
└── main
│ ├── kotlin
│ └── site
│ │ └── wenlong
│ │ └── dimens
│ │ ├── ui
│ │ ├── Colors.kt
│ │ ├── Font.kt
│ │ └── UI.kt
│ │ ├── base
│ │ ├── BaseDialogWrapper.kt
│ │ └── BaseAnAction.kt
│ │ ├── update
│ │ ├── VersionEnum.kt
│ │ ├── Update.kt
│ │ └── UpdateBalloon.kt
│ │ ├── constant
│ │ └── Constant.kt
│ │ ├── languages
│ │ ├── LanguagesFactory.kt
│ │ ├── Text.kt
│ │ ├── Chinese.kt
│ │ └── English.kt
│ │ ├── ext
│ │ ├── PluginExt.kt
│ │ ├── MessagesExt.kt
│ │ └── CalculateExt.kt
│ │ ├── action
│ │ ├── generate
│ │ │ ├── DimensGenerate.kt
│ │ │ └── DimensGenerateDialog.kt
│ │ └── converter
│ │ │ ├── DimensConverter.kt
│ │ │ └── DimensConverterDialog.kt
│ │ └── storages
│ │ └── Configuration.kt
│ └── resources
│ └── META-INF
│ ├── plugin.xml
│ ├── pluginIcon.svg
│ └── icons
│ └── pluginIcon.svg
├── .gitignore
├── LICENSE
├── .run
└── Run IDE with Plugin.run.xml
├── gradlew.bat
├── README-zh.md
├── README.md
└── gradlew
/.idea/.gitignore:
--------------------------------------------------------------------------------
1 | # Default ignored files
2 | /shelf/
3 | /workspace.xml
4 |
--------------------------------------------------------------------------------
/Zip/Dimens-Generating-3.1.0.zip:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wenlong-Guo/Dimens-Generating/HEAD/Zip/Dimens-Generating-3.1.0.zip
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Wenlong-Guo/Dimens-Generating/HEAD/gradle/wrapper/gradle-wrapper.jar
--------------------------------------------------------------------------------
/settings.gradle.kts:
--------------------------------------------------------------------------------
1 | pluginManagement {
2 | repositories {
3 | mavenCentral()
4 | gradlePluginPortal()
5 | }
6 | }
7 |
8 | rootProject.name = "Dimens-Generating"
--------------------------------------------------------------------------------
/.idea/vcs.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle.properties:
--------------------------------------------------------------------------------
1 | kotlin.stdlib.default.dependency=false
2 | # TODO temporary workaround for Kotlin 1.8.20+ (https://jb.gg/intellij-platform-kotlin-oom)
3 | kotlin.incremental.useClasspathSnapshot=false
4 |
--------------------------------------------------------------------------------
/.idea/kotlinc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
--------------------------------------------------------------------------------
/gradle/wrapper/gradle-wrapper.properties:
--------------------------------------------------------------------------------
1 | distributionBase=GRADLE_USER_HOME
2 | distributionPath=wrapper/dists
3 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
4 | zipStoreBase=GRADLE_USER_HOME
5 | zipStorePath=wrapper/dists
6 |
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/ui/Colors.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.ui
2 |
3 | import com.intellij.ui.JBColor
4 |
5 | /**
6 | * 颜色
7 | *
8 | * @author : 郭文龙
9 | * @Email : guowenlong20000@sina.com
10 | * @date : 2023/5/7 23:27
11 | */
12 | object Colors {
13 | val COLOR_BACKGROUND = JBColor(0x404040, 0x404040)
14 | }
--------------------------------------------------------------------------------
/.idea/misc.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/base/BaseDialogWrapper.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.base
2 |
3 | import com.intellij.openapi.ui.DialogWrapper
4 |
5 | /**
6 | * DialogWrapper的基类
7 | *
8 | * @author : 郭文龙
9 | * @Email : guowenlong20000@sina.com
10 | * @date : 2023/5/6 21:00
11 | */
12 | abstract class BaseDialogWrapper(canBeParent: Boolean) : DialogWrapper(canBeParent) {
13 | abstract fun showDialog()
14 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/update/VersionEnum.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.update
2 |
3 | /**
4 | * 版本
5 | *
6 | * @author : 郭文龙
7 | * @Email : guowenlong20000@sina.com
8 | * @date : 2023/5/20 22:07
9 | */
10 | enum class VersionEnum(val version: String, val content: String) {
11 | V310("3.1.0", "1.Replace Java with Kotlin language. 2.Build the project using Gradle. 3.Add update notes feature."),
12 | UNKNOWN("0.0.0", "")
13 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/constant/Constant.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.constant
2 |
3 | /**
4 | * 常量
5 | *
6 | * @author : 郭文龙
7 | * @Email : guowenlong20000@sina.com
8 | * @date : 2023/5/6 20:27
9 | */
10 | object Constant {
11 | const val DIMENS_XML_NAME = "dimens.xml"
12 | const val LAYOUT_FOLDER_NAME = "layout"
13 | const val LAYOUT_XML_NAME = ".xml"
14 | const val PLUGINS_NAME = "Dimens Generating"
15 | const val DP = "dp"
16 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/languages/LanguagesFactory.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.languages
2 |
3 | /**
4 | * 语言工厂类
5 | *
6 | * @author : 郭文龙
7 | * @Email : guowenlong20000@sina.com
8 | * @date : 2023/5/7 0:55
9 | */
10 | object LanguagesFactory {
11 | fun createText(languagesEnum: Int): Text {
12 | return when (languagesEnum) {
13 | 1 -> Chinese
14 | 0 -> English
15 | else -> English
16 | }
17 | }
18 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/ui/Font.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.ui
2 |
3 | import java.awt.Font
4 | import javax.swing.JComponent
5 |
6 | /**
7 | * 文本
8 | *
9 | * @author : 郭文龙
10 | * @Email : guowenlong20000@sina.com
11 | * @date : 2023/5/8 14:15
12 | */
13 |
14 | fun JComponent.titleFont() {
15 | this.font = Font(this.font.name, Font.PLAIN, 18)
16 | }
17 |
18 | fun JComponent.secondTitleFont() {
19 | this.font = Font(this.font.name, Font.PLAIN, 16)
20 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/base/BaseAnAction.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.base
2 |
3 | import com.intellij.openapi.actionSystem.AnAction
4 | import com.intellij.openapi.actionSystem.AnActionEvent
5 | import site.wenlong.dimens.storages.Configuration
6 |
7 | /**
8 | * AnAction的基类
9 | *
10 | * @author : 郭文龙
11 | * @Email : guowenlong20000@sina.com
12 | * @date : 2023/5/6 20:22
13 | */
14 | abstract class BaseAnAction : AnAction() {
15 | val configuration = Configuration.getInstance()
16 | }
--------------------------------------------------------------------------------
/.idea/gradle.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/ext/PluginExt.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.ext
2 |
3 | import com.intellij.ide.plugins.IdeaPluginDescriptor
4 | import com.intellij.ide.plugins.PluginManagerCore
5 | import com.intellij.openapi.extensions.PluginId
6 |
7 | /**
8 | * 本插件信息
9 | *
10 | * @author : 郭文龙
11 | * @Email : guowenlong20000@sina.com
12 | * @date : 2023/5/20 1:30
13 | */
14 | const val INITIAL_VERSION = "0.0.0"
15 |
16 | const val PLUGIN_ID = "com.guowenlong.dimens"
17 |
18 | const val VERSION_PROPERTY = "$PLUGIN_ID.version"
19 |
20 | val descriptor: IdeaPluginDescriptor by lazy { PluginManagerCore.getPlugin(PluginId.getId(PLUGIN_ID))!! }
21 |
22 | val version: String by lazy { descriptor.version }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .gradle
2 | build/
3 | !gradle/wrapper/gradle-wrapper.jar
4 | !**/src/main/**/build/
5 | !**/src/test/**/build/
6 |
7 | ### IntelliJ IDEA ###
8 | .idea/modules.xml
9 | .idea/jarRepositories.xml
10 | .idea/compiler.xml
11 | .idea/libraries/
12 | *.iws
13 | *.iml
14 | *.ipr
15 | out/
16 | !**/src/main/**/out/
17 | !**/src/test/**/out/
18 |
19 | ### Eclipse ###
20 | .apt_generated
21 | .classpath
22 | .factorypath
23 | .project
24 | .settings
25 | .springBeans
26 | .sts4-cache
27 | bin/
28 | !**/src/main/**/bin/
29 | !**/src/test/**/bin/
30 |
31 | ### NetBeans ###
32 | /nbproject/private/
33 | /nbbuild/
34 | /dist/
35 | /nbdist/
36 | /.nb-gradle/
37 |
38 | ### VS Code ###
39 | .vscode/
40 |
41 | ### Mac OS ###
42 | .DS_Store
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/ext/MessagesExt.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.ext
2 |
3 | import com.intellij.openapi.application.ApplicationManager
4 | import com.intellij.openapi.ui.Messages
5 | import site.wenlong.dimens.constant.Constant
6 |
7 | /**
8 | * Messages扩展
9 | *
10 | * @author : 郭文龙
11 | * @Email : guowenlong20000@sina.com
12 | * @date : 2023/5/6 22:58
13 | */
14 |
15 | fun showErrorMessage(message: String) {
16 | ApplicationManager.getApplication().invokeLater {
17 |
18 | Messages.showMessageDialog(
19 | message,
20 | Constant.PLUGINS_NAME,
21 | Messages.getErrorIcon()
22 | )
23 | }
24 | }
25 |
26 | fun showMessage(message: String) {
27 | ApplicationManager.getApplication().invokeLater {
28 | Messages.showMessageDialog(
29 | message,
30 | Constant.PLUGINS_NAME,
31 | Messages.getInformationIcon()
32 | )
33 | }
34 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2018 Wenlong Guo
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/ext/CalculateExt.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.ext
2 |
3 | import java.text.DecimalFormat
4 | import java.text.NumberFormat
5 | import java.util.*
6 |
7 | /**
8 | * 计算
9 | *
10 | * @author : 郭文龙
11 | * @Email : guowenlong20000@sina.com
12 | * @date : 2023/5/10 20:34
13 | */
14 | fun targetDimension(dimens: Float, length: Int, scale: Float): String? {
15 | println("dimens: ${dimens}")
16 | println("length: ${length}")
17 | println("scale: ${scale}")
18 |
19 | return formatDecimal((dimens / scale).toDouble(), length)
20 | }
21 |
22 | fun scale(originDimension: Float, toDimension: Float): Float {
23 | return originDimension / toDimension
24 | }
25 |
26 | fun formatDecimal(originNumber: Double, length: Int): String? {
27 | val sb = StringBuilder("0.")
28 | for (l in 0 until length) {
29 | sb.append("#")
30 | }
31 | val decimal = DecimalFormat(sb.toString()).format(originNumber)
32 | val numberFormat = NumberFormat.getNumberInstance(Locale.getDefault())
33 | numberFormat.isGroupingUsed = false
34 | return numberFormat.format(java.lang.Double.valueOf(decimal))
35 | }
--------------------------------------------------------------------------------
/.run/Run IDE with Plugin.run.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 | true
20 | true
21 | false
22 | false
23 |
24 |
25 |
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/languages/Text.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.languages
2 |
3 | /**
4 | * 文本接口
5 | *
6 | * @author : 郭文龙
7 | * @Email : guowenlong20000@sina.com
8 | * @date : 2023/5/6 23:06
9 | */
10 |
11 | interface Text {
12 | val titleOne: String
13 | val cover: String
14 | val decimal: String
15 | val minWidth: String
16 | val folder: String
17 | val bit: String
18 | val more: String
19 | val titleTwo: String
20 | val single: String
21 | val multi: String
22 | val advancedOption: String
23 | val genarate: String
24 | val tipsErrorFile: String
25 | val layoutTipsErrorFile: String
26 | val tipsErrorNumber: String
27 | val tipsCreateFileFailed: String
28 | val tipsCreateFileError: String
29 | val tipsGenerateSuccess: String
30 | val tipsGenerateFail: String
31 | val tipsConvertSuccess: String
32 | val tipsConvertFail: String
33 | val tipsDimensExists: String
34 | val tipsInputEmpty: String
35 | val tipsInputZero: String
36 | val tipsConvertTitle: String
37 | val tipsConvertTip1: String
38 | val tipsConvertDP: String
39 | val tipsConvertSP: String
40 | val tipsConvertEP1: String
41 | val tipsConvertEP2: String
42 | val tipsConvertButton: String
43 | val language :String
44 | val converting :String
45 | val exceptionOfFileError :String
46 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/action/generate/DimensGenerate.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.action.generate
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.intellij.openapi.actionSystem.PlatformDataKeys
5 | import com.intellij.openapi.project.Project
6 | import com.intellij.openapi.ui.Messages
7 | import com.intellij.openapi.vfs.VirtualFile
8 | import site.wenlong.dimens.base.BaseAnAction
9 | import site.wenlong.dimens.constant.Constant
10 | import site.wenlong.dimens.ext.showErrorMessage
11 | import site.wenlong.dimens.languages.LanguagesFactory.createText
12 |
13 | /**
14 | * 生成dimens文件
15 | *
16 | * @author : 郭文龙
17 | * @Email : guowenlong20000@sina.com
18 | * @date : 2023/5/7 0:58
19 | */
20 | class DimensGenerate : BaseAnAction() {
21 | override fun actionPerformed(event: AnActionEvent) {
22 | val currentFile = event.getData(PlatformDataKeys.VIRTUAL_FILE) ?: throw Exception("plugins compatibility error")
23 | val project = event.getData(PlatformDataKeys.PROJECT) ?: throw Exception("plugins compatibility error")
24 | when {
25 | isDimensFile(currentFile) -> {
26 | DimensGenerateDialog(currentFile, project).showFrame()
27 | }
28 |
29 | else -> {
30 | showErrorMessage(createText(configuration.languageIndex).tipsErrorFile)
31 | }
32 | }
33 | }
34 |
35 | private fun isDimensFile(currentFile: VirtualFile): Boolean {
36 | return currentFile.name == Constant.DIMENS_XML_NAME
37 | }
38 |
39 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/action/converter/DimensConverter.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.action.converter
2 |
3 | import com.intellij.openapi.actionSystem.AnActionEvent
4 | import com.intellij.openapi.actionSystem.PlatformDataKeys
5 | import com.intellij.openapi.ui.Messages
6 | import com.intellij.openapi.vfs.VirtualFile
7 | import site.wenlong.dimens.base.BaseAnAction
8 | import site.wenlong.dimens.constant.Constant
9 | import site.wenlong.dimens.ext.showErrorMessage
10 | import site.wenlong.dimens.languages.LanguagesFactory
11 |
12 | /**
13 | * 转换layout.xml或layout文件夹下所有layout的action
14 | *
15 | * @author : 郭文龙
16 | * @Email : guowenlong20000@sina.com
17 | * @date : 2023/5/6 20:52
18 | */
19 | class DimensConverter : BaseAnAction() {
20 | override fun actionPerformed(event: AnActionEvent) {
21 | val currentFile = event.getData(PlatformDataKeys.VIRTUAL_FILE) ?: throw Exception("plugins compatibility error")
22 | val project = event.getData(PlatformDataKeys.PROJECT) ?: throw Exception("plugins compatibility error")
23 | when {
24 | isLayoutFolder(currentFile) -> {
25 | DimensConverterDialog(currentFile, project, true).showFrame()
26 | }
27 |
28 | isLayoutXml(currentFile) -> {
29 | DimensConverterDialog(currentFile, project, false).showFrame()
30 | }
31 |
32 | else -> {
33 | showErrorMessage(LanguagesFactory.createText(configuration.languageIndex).layoutTipsErrorFile)
34 | }
35 | }
36 | }
37 |
38 | /**
39 | * 是否是layout文件夹
40 | */
41 | private fun isLayoutFolder(currentFile: VirtualFile?): Boolean {
42 | return currentFile != null && currentFile.name == Constant.LAYOUT_FOLDER_NAME
43 | }
44 |
45 | /**
46 | * 是否是layout.xml文件
47 | */
48 | private fun isLayoutXml(currentFile: VirtualFile?): Boolean {
49 | return currentFile != null && currentFile.name.endsWith(Constant.LAYOUT_XML_NAME)
50 | }
51 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/storages/Configuration.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.storages
2 |
3 | import com.intellij.openapi.application.ApplicationManager
4 | import com.intellij.openapi.components.PersistentStateComponent
5 | import com.intellij.openapi.components.State
6 | import com.intellij.openapi.components.Storage
7 | import com.intellij.util.xmlb.XmlSerializerUtil
8 |
9 | /**
10 | * 存储数据
11 | *
12 | * @author : 郭文龙
13 | * @Email : guowenlong20000@sina.com
14 | * @date : 2023/5/6 20:24
15 | */
16 | @State(name = "Configuration", storages = [Storage(value = "\$APP_CONFIG$/Configuration.xml")])
17 | class Configuration : PersistentStateComponent {
18 | companion object {
19 | fun getInstance(): Configuration {
20 | return ApplicationManager.getApplication().getService(Configuration::class.java)
21 | }
22 | }
23 |
24 | /**
25 | * 是否覆盖
26 | */
27 | var isOverride = false
28 |
29 | /**
30 | * 是否保留小数点
31 | */
32 | var isKeepDecimal = false
33 |
34 | /**
35 | * 是否设置最小宽度
36 | */
37 | var isMinWidth = false
38 |
39 | /**
40 | * 是否设置重命名文件件中间内容
41 | */
42 | var isReName = false
43 |
44 | /**
45 | * 是否是单个生成
46 | */
47 | var isSingle = false
48 |
49 | /**
50 | * 小数点位数
51 | */
52 | var decimalPlace = 2
53 |
54 | /**
55 | * 原始宽度
56 | */
57 | var originWidth = 360f
58 |
59 | /**
60 | * 文件夹中间名字
61 | */
62 | var folderName = "sw"
63 |
64 | /**
65 | * 单个生成的dimens文件的宽度基准
66 | */
67 | var single = "400"
68 |
69 | /**
70 | * 多个生成的dimens文件的宽度基准集合
71 | */
72 | var multi = "300,320,340,360,380,400,420,440,460,480,500"
73 |
74 | /**
75 | * 语言角标
76 | */
77 | var languageIndex = 0
78 |
79 | /**
80 | * dp dip的前缀
81 | */
82 | var dp = "length_"
83 |
84 | /**
85 | * sp 的前缀
86 | */
87 | var sp = "font_"
88 |
89 | override fun getState(): Configuration = this
90 |
91 | override fun loadState(state: Configuration) = XmlSerializerUtil.copyBean(state, this)
92 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/update/Update.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.update
2 |
3 | import com.intellij.ide.util.PropertiesComponent
4 | import com.intellij.openapi.project.Project
5 | import com.intellij.openapi.startup.StartupActivity
6 | import site.wenlong.dimens.ext.INITIAL_VERSION
7 | import site.wenlong.dimens.ext.VERSION_PROPERTY
8 | import site.wenlong.dimens.ext.version
9 |
10 | /**
11 | * 更新监查
12 | *
13 | * @author : 郭文龙
14 | * @Email : guowenlong20000@sina.com
15 | * @date : 2023/5/20 1:27
16 | */
17 | class Update : StartupActivity {
18 |
19 | private val properties: PropertiesComponent by lazy { PropertiesComponent.getInstance() }
20 |
21 | private val lastVersionString by lazy { properties.getValue(VERSION_PROPERTY, INITIAL_VERSION) }
22 |
23 | private val currentVersionString by lazy { version }
24 |
25 | override fun runActivity(project: Project) {
26 | if (isUpdated()) {
27 | UpdateBalloon().showBalloonWithLink(
28 | "" +
29 | "Dimens Generating has benn updated to V$currentVersionString" +
30 | " ",
31 | "" +
32 | "Thank you for downloading Dimens Generating!" +
33 | " " +
34 | "If you find it helpful, please click the button at the bottom to give me a Star." +
35 | " " +
36 | "This is the biggest encouragement for me." +
37 | " " +
38 | "Update Notes : " +
39 | " " +
40 | updateNotes(currentVersionString) +
41 | " " +
42 | " ",
43 | "https://github.com/Wenlong-Guo/Dimens-Generating"
44 | )
45 | }
46 | }
47 |
48 | private fun isUpdated(): Boolean = currentVersionString != lastVersionString
49 |
50 | private fun updateNotes(currentVersionString: String): String {
51 | VersionEnum.values().find {
52 | currentVersionString == it.version
53 | }?.also {
54 | return it.content
55 | }
56 | return VersionEnum.UNKNOWN.content
57 | }
58 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/languages/Chinese.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.languages
2 |
3 | /**
4 | * 中文
5 | *
6 | * @author : 郭文龙
7 | * @Email : guowenlong20000@sina.com
8 | * @date : 2023/5/6 23:05
9 | */
10 | object Chinese : Text {
11 | override val titleOne: String = "设置选项"
12 |
13 | override val cover: String = "是否覆盖已有文件"
14 |
15 | override val decimal: String = "保留几位小数的位数"
16 |
17 | override val minWidth: String = "设置所选中的dimens.xml的最小宽度(默认屏幕最小宽度360dp)"
18 |
19 | override val folder: String = "设置限定符名字(默认sw)(注意:命名不影响文件生成的规则)"
20 |
21 | override val bit: String = "位"
22 |
23 | override val more: String = "更多"
24 |
25 | override val titleTwo: String = "生成文件模式"
26 |
27 | override val single: String = "单个生成"
28 |
29 | override val multi: String = "多个生成"
30 |
31 | override val genarate: String = "生成Dimens"
32 |
33 | override val advancedOption: String = "扩展选项"
34 |
35 | override val tipsErrorFile: String = "您选择的文件不是dimens.xml,请重新选择"
36 |
37 | override val layoutTipsErrorFile: String = "您选择的文件不是layout文件夹或者xml文件,请重新选择"
38 |
39 | override val tipsErrorNumber: String = "请输入正确的数字"
40 |
41 | override val tipsCreateFileFailed: String = "文件不存在或者创建文件夹失败"
42 |
43 | override val tipsCreateFileError: String = "生成xml文件或文件夹异常,请提交问题到github,感谢"
44 |
45 | override val tipsGenerateSuccess: String = "生成成功"
46 |
47 | override val tipsConvertSuccess: String = "转换成功"
48 |
49 | override val tipsConvertFail: String = "转换失败"
50 |
51 | override val tipsDimensExists: String =
52 | "已经存在%s文件夹的dimens.xml文件\n请在Dimens Generating Tools的菜单中勾选可以覆盖源文件\n或者备份后删除重新生成"
53 |
54 | override val tipsGenerateFail: String = "生成失败"
55 |
56 | override val tipsInputEmpty: String = "不允许输入内容为空"
57 |
58 | override val tipsInputZero: String = "不允许输入数字为0"
59 |
60 | override val tipsConvertTitle: String = "转换设置"
61 |
62 | override val tipsConvertTip1: String = "小贴士:1.转换需要一点点时间\n 2.px不会转换"
63 |
64 | override val tipsConvertDP: String = "dp转换的前缀"
65 |
66 | override val tipsConvertSP: String = "sp转换的前缀"
67 |
68 | override val tipsConvertEP1: String = "(例如:length_ ,生成后为length_1)"
69 |
70 | override val tipsConvertEP2: String = "(例如:font_ ,生成后为font_1)"
71 |
72 | override val tipsConvertButton: String = "转换"
73 |
74 | override val language: String = "语言"
75 |
76 | override val converting: String = "转换中"
77 |
78 | override val exceptionOfFileError: String = "文件内部错误"
79 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/update/UpdateBalloon.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.update
2 |
3 | import com.intellij.ide.util.PropertiesComponent
4 | import com.intellij.openapi.ui.popup.Balloon
5 | import com.intellij.openapi.ui.popup.JBPopupFactory
6 | import com.intellij.ui.awt.RelativePoint
7 | import com.intellij.util.ui.JBUI
8 | import site.wenlong.dimens.ext.VERSION_PROPERTY
9 | import site.wenlong.dimens.ext.version
10 | import java.awt.*
11 | import java.awt.event.MouseAdapter
12 | import java.awt.event.MouseEvent
13 | import java.net.URI
14 | import javax.swing.BoxLayout
15 | import javax.swing.JLabel
16 | import javax.swing.JPanel
17 |
18 |
19 | /**
20 | * 更新提示
21 | *
22 | * @author : 郭文龙
23 | * @Email : guowenlong20000@sina.com
24 | * @date : 2023/5/20 22:53
25 | */
26 | class UpdateBalloon {
27 |
28 | private val properties: PropertiesComponent by lazy { PropertiesComponent.getInstance() }
29 |
30 | private val currentVersionString by lazy { version }
31 |
32 | var balloon: Balloon? = null
33 |
34 | fun showBalloonWithLink(title: String, message: String, linkUrl: String) {
35 | val panel = JPanel()
36 | panel.layout = BoxLayout(panel, BoxLayout.Y_AXIS)
37 | val titleLabel = JLabel(title)
38 | val messageLabel = JLabel(message)
39 | panel.add(titleLabel)
40 | panel.add(messageLabel)
41 | val linkLabel = JLabel("Please give me a Star. Thank you. ")
42 | linkLabel.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
43 | linkLabel.addMouseListener(object : MouseAdapter() {
44 | override fun mouseClicked(e: MouseEvent?) {
45 | try {
46 | Desktop.getDesktop().browse(URI(linkUrl))
47 | properties.setValue(VERSION_PROPERTY, currentVersionString)
48 | balloon?.dispose()
49 | } catch (ex: Exception) {
50 | ex.printStackTrace()
51 | }
52 | }
53 | })
54 | panel.add(linkLabel)
55 | balloon = JBPopupFactory.getInstance()
56 | .createBalloonBuilder(panel)
57 | .setCloseButtonEnabled(false)
58 | .setShadow(true)
59 | .setHideOnAction(false)
60 | .setContentInsets(JBUI.insets(30))
61 | .setHideOnClickOutside(false)
62 | .setHideOnFrameResize(false)
63 | .createBalloon()
64 | val point = Point(Toolkit.getDefaultToolkit().screenSize.width - 60, 60)
65 | val rPoint = RelativePoint(point)
66 | balloon?.show(rPoint, Balloon.Position.above)
67 | }
68 | }
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/ui/UI.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.ui
2 |
3 | import com.intellij.openapi.util.IconLoader
4 | import com.intellij.ui.components.labels.LinkLabel
5 | import com.intellij.util.IconUtil
6 | import com.intellij.util.ui.JBFont
7 | import com.intellij.util.ui.JBUI
8 | import com.intellij.util.ui.UIUtil
9 | import net.miginfocom.layout.CC
10 | import net.miginfocom.layout.LC
11 | import net.miginfocom.layout.LayoutUtil
12 | import net.miginfocom.swing.MigLayout
13 | import java.awt.Color
14 | import java.awt.image.RGBImageFilter
15 | import javax.swing.Icon
16 | import javax.swing.border.Border
17 |
18 | /**
19 | * UI
20 | */
21 | object UI {
22 |
23 | // 使用`get() = ...`以保证获得实时`ScaledFont`
24 | val defaultFont: JBFont get() = JBFont.create(UIUtil.getLabelFont(UIUtil.FontSize.NORMAL))
25 |
26 | data class FontPair(val primary: JBFont, val phonetic: JBFont)
27 |
28 | @JvmStatic
29 | fun Icon.disabled(): Icon = IconUtil.filterIcon(this, { DisabledFilter() }, null)
30 |
31 | private class DisabledFilter(color: Color = JBUI.CurrentTheme.Label.disabledForeground()) : RGBImageFilter() {
32 | private val rgb = color.rgb
33 |
34 | override fun filterRGB(x: Int, y: Int, argb: Int): Int {
35 | return argb and -0x1000000 or (rgb and 0x00ffffff)
36 | }
37 | }
38 |
39 | @JvmStatic
40 | fun getBordersColor(): Color = JBUI.CurrentTheme.Popup.borderColor(true)
41 |
42 | fun LinkLabel.setIcons(baseIcon: Icon) {
43 | icon = baseIcon
44 | disabledIcon = IconLoader.getDisabledIcon(baseIcon)
45 | setHoveringIcon(IconUtil.darker(baseIcon, 3))
46 | }
47 |
48 | fun migLayout(gapX: String = "0!", gapY: String = "0!", insets: String = "0") =
49 | MigLayout(LC().fill().gridGap(gapX, gapY).insets(insets))
50 |
51 | fun migLayoutVertical() =
52 | MigLayout(LC().flowY().fill().gridGap("0!", "0!").insets("0"))
53 |
54 | fun spanX(cells: Int = LayoutUtil.INF): CC = CC().spanX(cells)
55 |
56 | fun fill(): CC = CC().grow().push()
57 | fun fillX(): CC = CC().growX().pushX()
58 | fun fillY(): CC = CC().growY().pushY()
59 |
60 | fun wrap(): CC = CC().wrap()
61 |
62 | fun emptyBorder(topAndBottom: Int, leftAndRight: Int) = JBUI.Borders.empty(topAndBottom, leftAndRight)
63 |
64 | fun emptyBorder(offsets: Int) = JBUI.Borders.empty(offsets)
65 |
66 | fun lineAbove(): Border = JBUI.Borders.customLine(getBordersColor(), 1, 0, 0, 0)
67 |
68 | fun lineBelow(): Border = JBUI.Borders.customLine(getBordersColor(), 0, 0, 1, 0)
69 |
70 | fun lineToRight(): Border = JBUI.Borders.customLine(getBordersColor(), 0, 0, 0, 1)
71 |
72 | operator fun Border.plus(external: Border): Border = JBUI.Borders.merge(this, external, true)
73 | }
--------------------------------------------------------------------------------
/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/languages/English.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.languages
2 |
3 | /**
4 | * 英语
5 | *
6 | * @author : 郭文龙
7 | * @Email : guowenlong20000@sina.com
8 | * @date : 2023/5/6 23:14
9 | */
10 | object English : Text {
11 | override val titleOne = "Generate Options"
12 |
13 | override val cover = "Override existing files"
14 |
15 | override val decimal = "Keep the decimal point"
16 |
17 | override val minWidth = "Set the minimum width of the selected dimens.xml(Default 360dp)"
18 |
19 | override val folder = "Set qualifier name (default is \"sw\") (note: naming does not affect file generation rules)"
20 |
21 | override val bit = "bit"
22 |
23 | override val more = "more"
24 |
25 | override val titleTwo = "Generation Mode"
26 |
27 | override val single = "Single"
28 |
29 | override val multi = "Multiple"
30 |
31 | override val advancedOption = "advanced option"
32 |
33 | override val genarate = "Generate dimens"
34 |
35 | override val tipsErrorFile = "The file you selected is not dimens.xml, please re-select"
36 |
37 | override val layoutTipsErrorFile =
38 | "The file you selected is not layout folder or an xml file, please re-select"
39 |
40 | override val tipsErrorNumber = "Please enter the correct number"
41 |
42 | override val tipsCreateFileFailed: String = "File does not exist or folder creation failed"
43 |
44 | override val tipsCreateFileError: String =
45 | "Generate xml file or folder exception, please submit a question to github, thanks";
46 |
47 | override val tipsGenerateSuccess: String = "Generated successfully"
48 |
49 | override val tipsGenerateFail: String = "Generated fail"
50 |
51 | override val tipsConvertSuccess: String = "Converted successfully"
52 |
53 | override val tipsConvertFail: String = "Converter fail"
54 |
55 | override val tipsDimensExists: String =
56 | "The dimens.xml file of the %s folder already exists.\n Please check the Dimens Generating Tools menu to overwrite the source file \n or delete and regenerate after backup."
57 |
58 | override val tipsInputEmpty: String = "Do not allow input to be empty"
59 |
60 | override val tipsInputZero: String = "Do not allow input numbers to be 0"
61 |
62 | override val tipsConvertTitle: String = "Convert Option"
63 |
64 | override val tipsConvertTip1: String = "Tips:need a little time and px will not be convert"
65 |
66 | override val tipsConvertDP: String = "dp conversion prefix"
67 |
68 | override val tipsConvertSP: String = "sp conversion prefix"
69 |
70 | override val tipsConvertEP1: String = "(For example: length_ ,generation is length_1)"
71 |
72 | override val tipsConvertEP2: String = "(For example: font_ ,generation is font_1)"
73 |
74 | override val tipsConvertButton: String = "Convert"
75 |
76 | override val language: String = "Language"
77 |
78 | override val converting: String = "Converting..."
79 |
80 | override val exceptionOfFileError: String = "File Error"
81 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/plugin.xml:
--------------------------------------------------------------------------------
1 |
2 | com.guowenlong.dimens
3 | Dimens Generating
4 | 3.1.0
5 | Guo Wenlong
6 |
7 | Dimens Tool
9 |
10 |
11 |
12 | GitHub |
13 | Issues |
14 | Jetbrains |
15 | README
16 |
17 |
18 |
19 | A plugin that supports multiple screens by generating dimens.xml for any width screen size using minimum width qualifier.
20 |
21 | Features:
22 |
23 | Generate a dimens.xml file of the specified size (can be customized) based on the selected dimens.xml file.
24 | When the file to be generated already exists, you can control whether to override.
25 | Can generate multiple files of the specified size at the same time.
26 | Transformation layout.xml or layout folder DP DIP SP in the resource file.
27 |
28 |
29 | Usage:
30 |
31 | Choose origin dimens.xml -> right click -> Generate Dimens -> Edit options -> Click "Generate/生成" button.
32 | Choose layout.xml or layout folder -> right click -> Converter Dimens -> Edit options -> Click "Converter/转换" button.
33 |
34 |
35 |
36 | Tips:
37 |
38 | Welcome to improve your opinion.
39 | If you feel good,please star,thank you very much.
40 |
41 |
42 |
43 | To Do List:
44 |
45 | Support Japanese and Korean languages.
46 | Batch generate dp and sp with specified naming conventions in dimens.xml.
47 | Add folder naming convention for generating dimens.xml.
48 | Enhance conversion function and provide conversion utilities for px, dp, dip, and sp referenced in the code.
49 | View current phone screen information via adb.
50 |
51 |
52 |
53 | Send feedback
54 | ]]>
55 |
56 |
58 | V3.1.0 ⑴add update notes feature
59 | V3.0.0 ⑴refactor project using `Kotlin` and `Gradle`
60 | V2.0.5 ⑴fix android studio compatibility
61 | V2.0.4 ⑴fix issue #18
62 | V2.0.3 ⑴fix some V2.0.0 Bugs
63 | V2.0.0 ⑴fix issue #6 ⑵Add Logo ⑶Transformation layout.xml or layout folder DP DIP SP in the resource file
64 | V1.2.0 ⑴Redraw the UI ⑵Add save configuration function ⑶Support English and Chinese (4)Fix bug where resource attribute cannot be converted starting with "dip"
65 | V1.1.0 ⑴Custom decimal bit ⑵Generate multiple default parameter ⑶Custom qualifier name
66 | V1.0.1 Solve the problem that the specified size of the generated file is invalid
67 | V1.0.0 First Version
68 |
69 | ]]>
70 |
71 |
72 |
73 |
74 |
75 |
77 | com.intellij.modules.lang
78 | com.intellij.modules.all
79 | com.intellij.modules.platform
80 |
81 |
82 |
83 |
84 |
85 |
86 |
87 |
88 |
89 |
91 |
92 |
93 |
94 |
96 |
97 |
98 |
99 |
100 |
--------------------------------------------------------------------------------
/README-zh.md:
--------------------------------------------------------------------------------
1 | # Dimens-Generating
2 |
3 | ---
4 |
5 | [![Plugin Homepage][badge:plugin-homepage]][plugin-homepage]
6 | [![License][license-img]][license]
7 | [![Version][version-img]][plugin]
8 | [![Downloads][badge:downloads]][plugin-homepage]
9 |
10 | :ballot_box_with_check: 安卓最小宽度限定符插件.(生成多套dimens文件以及转换没有使用dimens的layout文件或者文件夹)
11 |
12 | [![Getting Started][badge:get-started-en]][get-started-en]
13 | [![开始使用][badge:get-started-zh]][get-started-zh]
14 |
15 | [//]: # ([![はじめに][badge:get-started-jp]][get-started-ja])
16 |
17 | [//]: # ([![시작하기][badge:get-started-ko]][get-started-ko])
18 |
19 | - [功能](#功能)
20 | - [用法](#用法)
21 | - [小贴士](#小贴士)
22 | - [变更说明](#变更说明)
23 | - [V3.1.0](#V310)
24 | - [V3.0.0](#V300)
25 | - [V2.0.5](#V205)
26 | - [V2.0.4](#V204)
27 | - [V2.0.3](#V203)
28 | - [V2.0.0](#V200)
29 | - [V1.2.0](#V120)
30 | - [V1.1.0](#V110)
31 | - [V1.0.1](#V101)
32 | - [V1.0.0](#V100)
33 | - [ScreenShot](#ScreenShot)
34 | - [License](#License)
35 | - [About My Github](#About-My-Github)
36 | - [About Me](#About-Me)
37 |
38 | ## 功能
39 |
40 | * 根据所选的dimens.xml文件生成指定尺寸(可自定义)的dimens.xml文件。
41 | * 当要生成的文件已经存在时,可以控制是否覆盖。
42 | * 可以同时生成多个指定大小的文件。
43 | * 在资源文件中,将layout.xml文件或layout文件夹中的DP、DIP或SP进行转换。
44 |
45 | ## 用法
46 |
47 | * 选择dimens.xml -> 右键 -> Generate Dimens -> 编辑选项 -> 点击 "Generate/生成" 按钮。
48 | * 选择layout.xml或者layout文件夹 -> 右键 -> Converter Dimens -> 编辑选项 -> 点击 "Converter/转换" 按钮。
49 |
50 | ## 小贴士
51 |
52 | * 欢迎提出您的意见和建议。
53 | * 如果您感觉该产品不错,请为我们点赞,非常感谢。
54 |
55 | ## 变更说明
56 |
57 | ### V3.1.0
58 | 1. 功能:增加更新日志提示的功能
59 |
60 | ### V3.0.0
61 | 1. 重构:使用 `Kotlin` 和 `Gradle` 构建项目。
62 |
63 | ### V2.0.5
64 | 1. 修复:与 Android Studio 兼容性问题
65 |
66 | ### V2.0.4
67 | 1. 修复 修复 issue #18
68 |
69 | ### V2.0.3
70 | 1. 修复:修复了一些 V2.0.0 中的错误。
71 |
72 | ### V2.0.0
73 | 1. 修复:修复 issue #6
74 | 2. 功能:添加 `Logo`
75 | 3. 功能:在资源文件中,将`layout.xml`或`layout folder`中的`DP` `DIP` `SP`进行转换。
76 |
77 | ### V1.2.0
78 | 1. 重新设计了用户界面
79 | 2. 添加了保存配置函数
80 | 3. 支持`英语`和`中文`
81 | 4. 修复了资源属性以“dip”开头时无法转换的错误。
82 |
83 | ### V1.1.0
84 | 1. 功能:自定义小数点位数
85 | 2. 功能:生成多个默认参数
86 | 3. 功能:自定义限定符名称
87 |
88 | ### V1.0.1
89 | 1. 修正:解决了生成文件的指定大小无效的问题。
90 |
91 | ### V1.0.0
92 | 1. 初始版本:生成 `dimens.xml`。
93 |
94 | ## ScreenShot
95 |
96 | 
97 |
98 | ## To Do List
99 |
100 | * 支持日语和韩语
101 | * 在dimens.xml批量生成指定命名规则的dp和sp
102 | * 增加生成dimens.xml的文件夹命名规则
103 | * 增强转换功能 附赠代码中引用的px dp dip sp的转换工具类
104 | * 通过adb查看当前手机的屏幕信息
105 |
106 | License
107 | -------
108 |
109 | Copyright 2023 Wenlong Guo
110 |
111 | Licensed under the Apache License, Version 2.0 (the "License");
112 | you may not use this file except in compliance with the License.
113 | You may obtain a copy of the License at
114 |
115 | http://www.apache.org/licenses/LICENSE-2.0
116 |
117 | Unless required by applicable law or agreed to in writing, software
118 | distributed under the License is distributed on an "AS IS" BASIS,
119 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
120 | See the License for the specific language governing permissions and
121 | limitations under the License.
122 |
123 | ## About Me
124 |
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 | - 📍 北京(Beijing)
138 | - 👨🎓 NKY.
139 | - 👩💻 8 years of work.
140 | - 🏢 待业 (求内推)
141 | - ☎️ 17600133786
142 | - wx : xiaoguo9745
143 | - 📧 [guowenlong20000@sina.com](mailto:guowenlong20000@sina.com)
144 | - ℹ️ 24k纯90后 没几年就35毕业了,毕业前开始总结安卓的经验,也算是给自己的这些年一个交代
145 |
146 | ## About My Github
147 |
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 | [license-img]: https://img.shields.io/badge/License-MIT-blue.svg
157 | [license]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/LICENSE
158 | [version-img]: https://img.shields.io/badge/Jetbrains%20Plugins-V3.1.0-blue.svg
159 | [plugin]: https://plugins.jetbrains.com/plugin/11290
160 |
161 | [badge:plugin-homepage]: https://img.shields.io/badge/plugin--homepage-Dimens--Generating-blue
162 | [badge:downloads]: https://img.shields.io/jetbrains/plugin/d/11290.svg?style=flat-square&colorB=blue
163 |
164 | [plugin-homepage]: https://plugins.jetbrains.com/plugin/11290-dimens-generating
165 | [dimens-generating-plugin]: https://plugins.jetbrains.com/plugin/11290-dimens-generating
166 | [plugin-homepage]: https://plugins.jetbrains.com/plugin/8579-translation
167 |
168 | [badge:get-started-en]: https://img.shields.io/badge/Get%20Started-English-4CAF50?style=flat-square
169 | [badge:get-started-zh]: https://img.shields.io/badge/%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8-%E4%B8%AD%E6%96%87-2196F3?style=flat-square
170 | [badge:get-started-jp]: https://img.shields.io/badge/%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB-%E6%97%A5%E6%9C%AC%E8%AA%9E-009688?style=flat-square
171 | [badge:get-started-ko]: https://img.shields.io/badge/%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-%ED%95%9C%EA%B5%AD%EC%96%B4-7CB342?style=flat-square
172 |
173 | [get-started-en]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/README.md
174 | [get-started-zh]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/README-zh.md
175 | [get-started-ja]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/README-ja.md
176 | [get-started-ko]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/README-ko.md
177 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Dimens-Generating
2 |
3 | ---
4 |
5 | [![Plugin Homepage][badge:plugin-homepage]][plugin-homepage]
6 | [![License][license-img]][license]
7 | [![Version][version-img]][plugin]
8 | [![Downloads][badge:downloads]][plugin-homepage]
9 |
10 | :ballot_box_with_check: A plugin that supports multiple screens by generating dimens.xml for any width screen size using minimum width qualifier.
11 |
12 | [![Getting Started][badge:get-started-en]][get-started-en]
13 | [![开始使用][badge:get-started-zh]][get-started-zh]
14 |
15 | [//]: # ([![はじめに][badge:get-started-jp]][get-started-ja])
16 |
17 | [//]: # ([![시작하기][badge:get-started-ko]][get-started-ko])
18 |
19 | - [Features](#Features)
20 | - [Usage](#Usage)
21 | - [Tips](#Tips)
22 | - [Change Notes](#Change-Notes)
23 | - [V3.1.0](#V310)
24 | - [V3.0.0](#V300)
25 | - [V2.0.5](#V205)
26 | - [V2.0.4](#V204)
27 | - [V2.0.3](#V203)
28 | - [V2.0.0](#V200)
29 | - [V1.2.0](#V120)
30 | - [V1.1.0](#V110)
31 | - [V1.0.1](#V101)
32 | - [V1.0.0](#V100)
33 | - [ScreenShot](#ScreenShot)
34 | - [License](#License)
35 | - [About My Github](#About-My-Github)
36 | - [About Me](#About-Me)
37 |
38 | ## Features
39 |
40 | * Generate a dimens.xml file of the specified size (can be customized) based on the selected dimens.xml file.
41 | * When the file to be generated already exists, you can control whether to override.
42 | * Can generate multiple files of the specified size at the same time.
43 | * Transformation layout.xml or layout folder DP DIP SP in the resource file.
44 |
45 | ## Usage
46 |
47 | * Choose origin dimens.xml -> right click -> Generate Dimens -> Edit options -> Click "Generate/生成" button.
48 | * Choose layout.xml or layout folder -> right click -> Converter Dimens -> Edit options -> Click "Converter/转换" button.
49 |
50 | ## Tips
51 |
52 | * Welcome to improve your opinion.
53 | * If you feel good,please star,thank you very much.
54 |
55 | ## Change Notes
56 |
57 | ### V3.1.0
58 | 1. feature : Add `Update notes` feature.
59 |
60 | ### V3.0.0
61 | 1. refactor : Building a project using `Kotlin` through `Gradle`.
62 |
63 | ### V2.0.5
64 | 1. fix android studio compatibility
65 |
66 | ### V2.0.4
67 | 1. fix : issue #18
68 |
69 | ### V2.0.3
70 | 1. fix : some V2.0.0 Bugs
71 |
72 | ### V2.0.0
73 | 1. fix : issue #6
74 | 2. feature : Add `Logo`
75 | 3. feature : Transformation `layout.xml` or `layout folder` `DP` `DIP` `SP` in the resource file
76 |
77 | ### V1.2.0
78 | 1. Redraw the UI
79 | 2. Add save configuration function
80 | 3. Support `English` and `Chinese`
81 | 4. Fix bug where resource attribute cannot be converted starting with "dip"
82 |
83 | ### V1.1.0
84 | 1. feature : Custom decimal bit
85 | 2. feature : Generate multiple default parameter
86 | 3. feature : Custom qualifier name
87 |
88 | ### V1.0.1
89 | 1. fix : Solve the problem that the specified size of the generated file is invalid
90 |
91 | ### V1.0.0
92 | 1. First Version generate `dimens.xml`
93 |
94 |
95 | ## ScreenShot
96 |
97 | 
98 |
99 | ## To Do List
100 |
101 | * Support Japanese and Korean languages
102 | * Batch generate dp and sp with specified naming conventions in dimens.xml
103 | * Add folder naming convention for generating dimens.xml
104 | * Enhance conversion function and provide conversion utilities for px, dp, dip, and sp referenced in the code
105 | * View current phone screen information via adb.
106 |
107 | License
108 | -------
109 |
110 | Copyright 2018 Wenlong Guo
111 |
112 | Licensed under the Apache License, Version 2.0 (the "License");
113 | you may not use this file except in compliance with the License.
114 | You may obtain a copy of the License at
115 |
116 | http://www.apache.org/licenses/LICENSE-2.0
117 |
118 | Unless required by applicable law or agreed to in writing, software
119 | distributed under the License is distributed on an "AS IS" BASIS,
120 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
121 | See the License for the specific language governing permissions and
122 | limitations under the License.
123 |
124 | ## About Me
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 | - 📍 北京(Beijing)
139 | - 👨🎓 NKY.
140 | - 👩💻 8 years of work.
141 | - 🏢 待业 (求内推)
142 | - ☎️ 17600133786
143 | - wx : xiaoguo9745
144 | - 📧 [guowenlong20000@sina.com](mailto:guowenlong20000@sina.com)
145 | - ℹ️ 24k纯90后 没几年就35毕业了,毕业前开始总结安卓的经验,也算是给自己的这些年一个交代
146 |
147 | ## About My Github
148 |
149 |
150 |
151 |
152 |
153 |
154 |
155 |
156 |
157 | [license-img]: https://img.shields.io/badge/License-MIT-blue.svg
158 | [license]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/LICENSE
159 | [version-img]: https://img.shields.io/badge/Jetbrains%20Plugins-V3.1.0-blue.svg
160 | [plugin]: https://plugins.jetbrains.com/plugin/11290
161 |
162 | [badge:plugin-homepage]: https://img.shields.io/badge/plugin--homepage-Dimens--Generating-blue
163 | [badge:downloads]: https://img.shields.io/jetbrains/plugin/d/11290.svg?style=flat-square&colorB=blue
164 |
165 | [plugin-homepage]: https://plugins.jetbrains.com/plugin/11290-dimens-generating
166 | [dimens-generating-plugin]: https://plugins.jetbrains.com/plugin/11290-dimens-generating
167 | [plugin-homepage]: https://plugins.jetbrains.com/plugin/8579-translation
168 |
169 | [badge:get-started-en]: https://img.shields.io/badge/Get%20Started-English-4CAF50?style=flat-square
170 | [badge:get-started-zh]: https://img.shields.io/badge/%E5%BC%80%E5%A7%8B%E4%BD%BF%E7%94%A8-%E4%B8%AD%E6%96%87-2196F3?style=flat-square
171 | [badge:get-started-jp]: https://img.shields.io/badge/%E3%81%AF%E3%81%98%E3%82%81%E3%81%AB-%E6%97%A5%E6%9C%AC%E8%AA%9E-009688?style=flat-square
172 | [badge:get-started-ko]: https://img.shields.io/badge/%EC%8B%9C%EC%9E%91%ED%95%98%EA%B8%B0-%ED%95%9C%EA%B5%AD%EC%96%B4-7CB342?style=flat-square
173 |
174 | [get-started-en]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/README.md
175 | [get-started-zh]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/README-zh.md
176 | [get-started-ja]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/README-ja.md
177 | [get-started-ko]: https://github.com/Wenlong-Guo/Dimens-Generating/blob/master/README-ko.md
178 |
--------------------------------------------------------------------------------
/gradlew:
--------------------------------------------------------------------------------
1 | #!/bin/sh
2 |
3 | #
4 | # Copyright © 2015-2021 the original authors.
5 | #
6 | # Licensed under the Apache License, Version 2.0 (the "License");
7 | # you may not use this file except in compliance with the License.
8 | # You may obtain a copy of the License at
9 | #
10 | # https://www.apache.org/licenses/LICENSE-2.0
11 | #
12 | # Unless required by applicable law or agreed to in writing, software
13 | # distributed under the License is distributed on an "AS IS" BASIS,
14 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | # See the License for the specific language governing permissions and
16 | # limitations under the License.
17 | #
18 |
19 | ##############################################################################
20 | #
21 | # Gradle start up script for POSIX generated by Gradle.
22 | #
23 | # Important for running:
24 | #
25 | # (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is
26 | # noncompliant, but you have some other compliant shell such as ksh or
27 | # bash, then to run this script, type that shell name before the whole
28 | # command line, like:
29 | #
30 | # ksh Gradle
31 | #
32 | # Busybox and similar reduced shells will NOT work, because this script
33 | # requires all of these POSIX shell features:
34 | # * functions;
35 | # * expansions «$var», «${var}», «${var:-default}», «${var+SET}»,
36 | # «${var#prefix}», «${var%suffix}», and «$( cmd )»;
37 | # * compound commands having a testable exit status, especially «case»;
38 | # * various built-in commands including «command», «set», and «ulimit».
39 | #
40 | # Important for patching:
41 | #
42 | # (2) This script targets any POSIX shell, so it avoids extensions provided
43 | # by Bash, Ksh, etc; in particular arrays are avoided.
44 | #
45 | # The "traditional" practice of packing multiple parameters into a
46 | # space-separated string is a well documented source of bugs and security
47 | # problems, so this is (mostly) avoided, by progressively accumulating
48 | # options in "$@", and eventually passing that to Java.
49 | #
50 | # Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS,
51 | # and GRADLE_OPTS) rely on word-splitting, this is performed explicitly;
52 | # see the in-line comments for details.
53 | #
54 | # There are tweaks for specific operating systems such as AIX, CygWin,
55 | # Darwin, MinGW, and NonStop.
56 | #
57 | # (3) This script is generated from the Groovy template
58 | # https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
59 | # within the Gradle project.
60 | #
61 | # You can find Gradle at https://github.com/gradle/gradle/.
62 | #
63 | ##############################################################################
64 |
65 | # Attempt to set APP_HOME
66 |
67 | # Resolve links: $0 may be a link
68 | app_path=$0
69 |
70 | # Need this for daisy-chained symlinks.
71 | while
72 | APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path
73 | [ -h "$app_path" ]
74 | do
75 | ls=$( ls -ld "$app_path" )
76 | link=${ls#*' -> '}
77 | case $link in #(
78 | /*) app_path=$link ;; #(
79 | *) app_path=$APP_HOME$link ;;
80 | esac
81 | done
82 |
83 | APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
84 |
85 | APP_NAME="Gradle"
86 | APP_BASE_NAME=${0##*/}
87 |
88 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
89 | DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
90 |
91 | # Use the maximum available, or set MAX_FD != -1 to use that value.
92 | MAX_FD=maximum
93 |
94 | warn () {
95 | echo "$*"
96 | } >&2
97 |
98 | die () {
99 | echo
100 | echo "$*"
101 | echo
102 | exit 1
103 | } >&2
104 |
105 | # OS specific support (must be 'true' or 'false').
106 | cygwin=false
107 | msys=false
108 | darwin=false
109 | nonstop=false
110 | case "$( uname )" in #(
111 | CYGWIN* ) cygwin=true ;; #(
112 | Darwin* ) darwin=true ;; #(
113 | MSYS* | MINGW* ) msys=true ;; #(
114 | NONSTOP* ) nonstop=true ;;
115 | esac
116 |
117 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
118 |
119 |
120 | # Determine the Java command to use to start the JVM.
121 | if [ -n "$JAVA_HOME" ] ; then
122 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
123 | # IBM's JDK on AIX uses strange locations for the executables
124 | JAVACMD=$JAVA_HOME/jre/sh/java
125 | else
126 | JAVACMD=$JAVA_HOME/bin/java
127 | fi
128 | if [ ! -x "$JAVACMD" ] ; then
129 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
130 |
131 | Please set the JAVA_HOME variable in your environment to match the
132 | location of your Java installation."
133 | fi
134 | else
135 | JAVACMD=java
136 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
137 |
138 | Please set the JAVA_HOME variable in your environment to match the
139 | location of your Java installation."
140 | fi
141 |
142 | # Increase the maximum file descriptors if we can.
143 | if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
144 | case $MAX_FD in #(
145 | max*)
146 | MAX_FD=$( ulimit -H -n ) ||
147 | warn "Could not query maximum file descriptor limit"
148 | esac
149 | case $MAX_FD in #(
150 | '' | soft) :;; #(
151 | *)
152 | ulimit -n "$MAX_FD" ||
153 | warn "Could not set maximum file descriptor limit to $MAX_FD"
154 | esac
155 | fi
156 |
157 | # Collect all arguments for the java command, stacking in reverse order:
158 | # * args from the command line
159 | # * the main class name
160 | # * -classpath
161 | # * -D...appname settings
162 | # * --module-path (only if needed)
163 | # * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables.
164 |
165 | # For Cygwin or MSYS, switch paths to Windows format before running java
166 | if "$cygwin" || "$msys" ; then
167 | APP_HOME=$( cygpath --path --mixed "$APP_HOME" )
168 | CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" )
169 |
170 | JAVACMD=$( cygpath --unix "$JAVACMD" )
171 |
172 | # Now convert the arguments - kludge to limit ourselves to /bin/sh
173 | for arg do
174 | if
175 | case $arg in #(
176 | -*) false ;; # don't mess with options #(
177 | /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath
178 | [ -e "$t" ] ;; #(
179 | *) false ;;
180 | esac
181 | then
182 | arg=$( cygpath --path --ignore --mixed "$arg" )
183 | fi
184 | # Roll the args list around exactly as many times as the number of
185 | # args, so each arg winds up back in the position where it started, but
186 | # possibly modified.
187 | #
188 | # NB: a `for` loop captures its iteration list before it begins, so
189 | # changing the positional parameters here affects neither the number of
190 | # iterations, nor the values presented in `arg`.
191 | shift # remove old arg
192 | set -- "$@" "$arg" # push replacement arg
193 | done
194 | fi
195 |
196 | # Collect all arguments for the java command;
197 | # * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
198 | # shell script including quotes and variable substitutions, so put them in
199 | # double quotes to make sure that they get re-expanded; and
200 | # * put everything else in single quotes, so that it's not re-expanded.
201 |
202 | set -- \
203 | "-Dorg.gradle.appname=$APP_BASE_NAME" \
204 | -classpath "$CLASSPATH" \
205 | org.gradle.wrapper.GradleWrapperMain \
206 | "$@"
207 |
208 | # Use "xargs" to parse quoted args.
209 | #
210 | # With -n1 it outputs one arg per line, with the quotes and backslashes removed.
211 | #
212 | # In Bash we could simply go:
213 | #
214 | # readarray ARGS < <( xargs -n1 <<<"$var" ) &&
215 | # set -- "${ARGS[@]}" "$@"
216 | #
217 | # but POSIX shell has neither arrays nor command substitution, so instead we
218 | # post-process each arg (as a line of input to sed) to backslash-escape any
219 | # character that might be a shell metacharacter, then use eval to reverse
220 | # that process (while maintaining the separation between arguments), and wrap
221 | # the whole thing up as a single "set" statement.
222 | #
223 | # This will of course break if any of these variables contains a newline or
224 | # an unmatched quote.
225 | #
226 |
227 | eval "set -- $(
228 | printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" |
229 | xargs -n1 |
230 | sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' |
231 | tr '\n' ' '
232 | )" '"$@"'
233 |
234 | exec "$JAVACMD" "$@"
235 |
--------------------------------------------------------------------------------
/.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 |
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/action/converter/DimensConverterDialog.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.action.converter
2 |
3 | import com.intellij.openapi.progress.ProgressIndicator
4 | import com.intellij.openapi.progress.ProgressManager
5 | import com.intellij.openapi.progress.Task
6 | import com.intellij.openapi.project.Project
7 | import com.intellij.openapi.vfs.VirtualFile
8 | import com.intellij.openapi.vfs.VirtualFileManager
9 | import net.miginfocom.swing.MigLayout
10 | import org.w3c.dom.Element
11 | import org.w3c.dom.Node
12 | import org.w3c.dom.NodeList
13 | import site.wenlong.dimens.ext.showErrorMessage
14 | import site.wenlong.dimens.ext.showMessage
15 | import site.wenlong.dimens.languages.LanguagesFactory.createText
16 | import site.wenlong.dimens.storages.Configuration
17 | import site.wenlong.dimens.ui.Colors
18 | import site.wenlong.dimens.ui.secondTitleFont
19 | import site.wenlong.dimens.ui.titleFont
20 | import java.awt.BorderLayout
21 | import java.awt.Dimension
22 | import java.awt.FlowLayout
23 | import java.awt.Panel
24 | import java.awt.event.ItemEvent
25 | import java.io.File
26 | import java.util.*
27 | import javax.swing.*
28 | import javax.swing.event.DocumentEvent
29 | import javax.swing.event.DocumentListener
30 | import javax.xml.parsers.DocumentBuilderFactory
31 | import javax.xml.transform.TransformerFactory
32 | import javax.xml.transform.dom.DOMSource
33 | import javax.xml.transform.stream.StreamResult
34 |
35 |
36 | /**
37 | * 转换layout.xml或layout文件夹下所有layout的对话框
38 | *
39 | * @author : 郭文龙
40 | * @Email : guowenlong20000@sina.com
41 | * @date : 2023/5/6 20:48
42 | */
43 | class DimensConverterDialog(
44 | private val currentFile: VirtualFile,
45 | private val project: Project,
46 | private val isFolder: Boolean
47 | ) : JFrame() {
48 | private val configuration = Configuration.getInstance()
49 |
50 | private val languageJComboBox by lazy {
51 | JComboBox().also {
52 | it.addItem("English")
53 | it.addItem("中文")
54 | }
55 | }
56 |
57 | private val titleLabel by lazy {
58 | JLabel(createText(configuration.languageIndex).tipsConvertTitle).also {
59 | it.isOpaque = true
60 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
61 | it.background = Colors.COLOR_BACKGROUND
62 | it.titleFont()
63 | }
64 | }
65 |
66 | private val language by lazy {
67 | JLabel(createText(configuration.languageIndex).language).also {
68 | it.isOpaque = true
69 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
70 | it.background = Colors.COLOR_BACKGROUND
71 | it.preferredSize = Dimension(100, preferredSize.height)
72 | }
73 | }
74 |
75 | private val tips by lazy {
76 | JLabel(createText(configuration.languageIndex).tipsConvertTip1).also {
77 | it.isOpaque = true
78 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
79 | it.background = Colors.COLOR_BACKGROUND
80 | }
81 | }
82 |
83 | private val convertDp by lazy {
84 | JLabel(createText(configuration.languageIndex).tipsConvertDP).also {
85 | it.isOpaque = true
86 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
87 | it.background = Colors.COLOR_BACKGROUND
88 | it.secondTitleFont()
89 | }
90 | }
91 |
92 | private val convertDpTextField by lazy {
93 | JTextField(configuration.dp).also {
94 | it.isOpaque = true
95 | it.border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
96 | it.preferredSize = Dimension(100, preferredSize.height)
97 | }
98 | }
99 |
100 | private val convertDpTips by lazy {
101 | JLabel(createText(configuration.languageIndex).tipsConvertEP1).also {
102 | it.isOpaque = true
103 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
104 | it.background = Colors.COLOR_BACKGROUND
105 | }
106 | }
107 |
108 | private val convertSp by lazy {
109 | JLabel(createText(configuration.languageIndex).tipsConvertSP).also {
110 | it.isOpaque = true
111 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
112 | it.background = Colors.COLOR_BACKGROUND
113 | it.secondTitleFont()
114 | }
115 | }
116 | private val convertSpTextField by lazy {
117 | JTextField(configuration.sp).also {
118 | it.isOpaque = true
119 | it.border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
120 | it.preferredSize = Dimension(100, preferredSize.height)
121 | }
122 | }
123 |
124 | private val convertSpTips by lazy {
125 | JLabel(createText(configuration.languageIndex).tipsConvertEP2).also {
126 | it.isOpaque = true
127 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
128 | it.background = Colors.COLOR_BACKGROUND
129 | }
130 | }
131 |
132 | private val converter by lazy {
133 | JButton(createText(configuration.languageIndex).tipsConvertButton).also {
134 | it.border = BorderFactory.createEmptyBorder(10, 20, 10, 20)
135 | it.secondTitleFont()
136 | }
137 | }
138 |
139 | init {
140 | val root = JPanel()
141 | val migLayout = MigLayout("wrap")
142 | root.layout = migLayout
143 |
144 | root.add(titleLabel)
145 |
146 | val languagePanel = Panel()
147 | val languageBoxLayout = BoxLayout(languagePanel, BoxLayout.X_AXIS)
148 | languagePanel.background = Colors.COLOR_BACKGROUND
149 | languagePanel.foreground = Colors.COLOR_BACKGROUND
150 | languagePanel.layout = languageBoxLayout
151 | languagePanel.add(language)
152 | languagePanel.add(languageJComboBox)
153 | root.add(languagePanel)
154 |
155 | root.add(tips)
156 |
157 | root.add(convertDp)
158 | val dpPanel = JPanel()
159 | val dpLayout = BoxLayout(dpPanel, BoxLayout.X_AXIS)
160 | dpPanel.layout = dpLayout
161 | dpPanel.add(convertDpTextField, BorderLayout.CENTER)
162 | dpPanel.border = BorderFactory.createEmptyBorder(0, 10, 0, 10)
163 | dpPanel.add(convertDpTextField)
164 | dpPanel.add(convertDpTips)
165 | root.add(dpPanel)
166 |
167 | root.add(convertSp)
168 | val spPanel = JPanel()
169 | val spLayout = BoxLayout(spPanel, BoxLayout.X_AXIS)
170 | spPanel.layout = spLayout
171 | spPanel.add(convertSpTextField, BorderLayout.CENTER)
172 | spPanel.border = BorderFactory.createEmptyBorder(0, 10, 0, 10)
173 | spPanel.add(convertSpTextField)
174 | spPanel.add(convertSpTips)
175 | root.add(spPanel)
176 |
177 | val buttonJPanel = JPanel(FlowLayout(FlowLayout.CENTER, 0, 20))
178 | buttonJPanel.add(converter)
179 | buttonJPanel.preferredSize = Dimension(600, preferredSize.height)
180 |
181 | root.add(buttonJPanel)
182 |
183 | add(root)
184 |
185 | pack()
186 | initSaveConfiguration()
187 | initClick()
188 | initTextField()
189 | initData(currentFile, project)
190 | }
191 |
192 | private fun initSaveConfiguration() {
193 | addWindowStateListener { configuration.state }
194 | }
195 |
196 | private fun initTextField() {
197 | convertDpTextField.document.addDocumentListener(object : DocumentListener {
198 | override fun insertUpdate(e: DocumentEvent) {
199 | configuration.dp = convertDpTextField.text.toString()
200 | }
201 |
202 | override fun removeUpdate(e: DocumentEvent) {
203 | configuration.dp = convertDpTextField.text.toString()
204 | }
205 |
206 | override fun changedUpdate(e: DocumentEvent) {}
207 | })
208 |
209 | convertSpTextField.document.addDocumentListener(object : DocumentListener {
210 | override fun insertUpdate(e: DocumentEvent) {
211 | configuration.sp = convertSpTextField.text.toString()
212 | }
213 |
214 | override fun removeUpdate(e: DocumentEvent) {
215 | configuration.sp = convertSpTextField.text.toString()
216 | }
217 |
218 | override fun changedUpdate(e: DocumentEvent) {}
219 | })
220 | }
221 |
222 | private fun initClick() {
223 | languageJComboBox.addItemListener { e: ItemEvent ->
224 | if (e.stateChange == ItemEvent.SELECTED) {
225 | configuration.languageIndex = languageJComboBox.selectedIndex
226 | toggleLanguage()
227 | }
228 | }
229 | }
230 |
231 | fun showFrame() {
232 | title = createText(configuration.languageIndex).tipsConvertTitle
233 | setSize(640, 450)
234 | setLocationRelativeTo(null)
235 | isVisible = true
236 | }
237 |
238 | private fun toggleLanguage() {
239 | title = createText(configuration.languageIndex).tipsConvertTitle
240 | titleLabel.text = createText(configuration.languageIndex).tipsConvertTitle
241 | language.text = createText(configuration.languageIndex).language
242 | tips.text = createText(configuration.languageIndex).tipsConvertTip1
243 | convertDp.text = createText(configuration.languageIndex).tipsConvertDP
244 | convertDpTips.text = createText(configuration.languageIndex).tipsConvertEP1
245 | convertSp.text = createText(configuration.languageIndex).tipsConvertSP
246 | convertSpTips.text = createText(configuration.languageIndex).tipsConvertEP2
247 | converter.text = createText(configuration.languageIndex).tipsConvertButton
248 | }
249 |
250 | private fun initData(currentFile: VirtualFile, project: Project) {
251 | languageJComboBox.selectedIndex = configuration.languageIndex
252 | converter.addActionListener {
253 | if (isFolder) {
254 | convertLayoutFolder(currentFile, project)
255 | } else {
256 | convertOneLayoutXmlFile(currentFile, project)
257 | }
258 | dispose()
259 | }
260 | }
261 |
262 | private fun convertOneLayoutXmlFile(currentFile: VirtualFile, project: Project) {
263 | ProgressManager.getInstance()
264 | .run(object : Task.Backgroundable(project, createText(configuration.languageIndex).converting) {
265 | override fun run(progressIndicator: ProgressIndicator) {
266 | try {
267 | convert(currentFile)
268 | VirtualFileManager.getInstance().syncRefresh()
269 | showMessage(createText(configuration.languageIndex).tipsConvertSuccess)
270 | } catch (e: Exception) {
271 | showErrorMessage(createText(configuration.languageIndex).tipsConvertFail)
272 | }
273 | }
274 | })
275 | }
276 |
277 | private fun convertLayoutFolder(currentFile: VirtualFile, project: Project?) {
278 | ProgressManager.getInstance()
279 | .run(object : Task.Backgroundable(project, createText(configuration.languageIndex).converting) {
280 | override fun run(progressIndicator: ProgressIndicator) {
281 | try {
282 | val children = currentFile.children
283 | for (child in children) {
284 | convert(child)
285 | }
286 | showMessage(createText(configuration.languageIndex).tipsConvertSuccess)
287 | } catch (e: Exception) {
288 | showErrorMessage(createText(configuration.languageIndex).tipsConvertFail)
289 | }
290 | }
291 | })
292 | }
293 |
294 | @Throws(Exception::class)
295 | private fun convert(child: VirtualFile) {
296 | val factory = DocumentBuilderFactory.newInstance()
297 | val builder = factory.newDocumentBuilder()
298 | val file = File(
299 | child.canonicalPath ?: throw Exception(createText(configuration.languageIndex).exceptionOfFileError)
300 | )
301 | val document = builder.parse(file)
302 | val root: Element = document.documentElement
303 | traverseNode(root.childNodes)
304 | val transformerFactory = TransformerFactory.newInstance()
305 | val transformer = transformerFactory.newTransformer()
306 | val source = DOMSource(document)
307 | val result = StreamResult(file)
308 | transformer.transform(source, result)
309 | }
310 |
311 | private fun traverseNode(nodeList: NodeList) {
312 | for (i in 0 until nodeList.length) {
313 | val node: Node = nodeList.item(i)
314 | if (node.nodeType == Element.ELEMENT_NODE) {
315 | // 处理元素节点
316 | val element = node as Element
317 | println("Element name: ${element.nodeName}")
318 | traverseAttributes(element)
319 |
320 | // 遍历子节点
321 | if (element.hasChildNodes()) {
322 | traverseNode(element.childNodes)
323 | }
324 | }
325 | }
326 | }
327 |
328 | private fun traverseAttributes(element: Element) {
329 | for (i in 0 until element.attributes.length) {
330 | val item = element.attributes.item(i)
331 | println("Attribute name: ${item.nodeName}")
332 | println("Attribute value: ${item.nodeValue}")
333 | when {
334 | item.nodeValue.endsWith("dip") -> {
335 | item.nodeValue =
336 | "@dimen/" + configuration.dp + item.nodeValue.substring(0, item.nodeValue.length - 3)
337 | }
338 |
339 | item.nodeValue.endsWith("dp") -> {
340 | item.nodeValue =
341 | "@dimen/" + configuration.dp + item.nodeValue.substring(0, item.nodeValue.length - 2)
342 | }
343 |
344 | item.nodeValue.endsWith("sp") -> {
345 | item.nodeValue =
346 | "@dimen/" + configuration.sp + item.nodeValue.substring(0, item.nodeValue.length - 2)
347 | }
348 |
349 | item.nodeValue.endsWith("px") -> {
350 | //todo 后续版本完善
351 | }
352 | }
353 | }
354 | }
355 | }
--------------------------------------------------------------------------------
/src/main/resources/META-INF/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
241 |
242 |
--------------------------------------------------------------------------------
/src/main/resources/META-INF/icons/pluginIcon.svg:
--------------------------------------------------------------------------------
1 |
2 |
3 |
241 |
242 |
--------------------------------------------------------------------------------
/src/main/kotlin/site/wenlong/dimens/action/generate/DimensGenerateDialog.kt:
--------------------------------------------------------------------------------
1 | package site.wenlong.dimens.action.generate
2 |
3 | import com.intellij.openapi.project.Project
4 | import com.intellij.openapi.vfs.VirtualFile
5 | import com.intellij.openapi.vfs.VirtualFileManager
6 | import net.miginfocom.swing.MigLayout
7 | import org.w3c.dom.Document
8 | import org.w3c.dom.Element
9 | import org.w3c.dom.NodeList
10 | import site.wenlong.dimens.constant.Constant
11 | import site.wenlong.dimens.ext.showErrorMessage
12 | import site.wenlong.dimens.ext.showMessage
13 | import site.wenlong.dimens.ext.targetDimension
14 | import site.wenlong.dimens.languages.LanguagesFactory
15 | import site.wenlong.dimens.storages.Configuration
16 | import site.wenlong.dimens.ui.Colors
17 | import site.wenlong.dimens.ui.secondTitleFont
18 | import site.wenlong.dimens.ui.titleFont
19 | import java.awt.Dimension
20 | import java.awt.FlowLayout
21 | import java.awt.Panel
22 | import java.awt.event.ItemEvent
23 | import java.io.File
24 | import javax.swing.*
25 | import javax.swing.event.ChangeEvent
26 | import javax.swing.event.DocumentEvent
27 | import javax.swing.event.DocumentListener
28 | import javax.xml.parsers.DocumentBuilderFactory
29 | import javax.xml.transform.TransformerFactory
30 | import javax.xml.transform.dom.DOMSource
31 | import javax.xml.transform.stream.StreamResult
32 |
33 |
34 | /**
35 | * 生成dimens文件的对话框
36 | *
37 | * @author : 郭文龙
38 | * @Email : guowenlong20000@sina.com
39 | * @date : 2023/5/6 20:12
40 | */
41 | class DimensGenerateDialog(private val currentFile: VirtualFile, private val project: Project) : JFrame() {
42 |
43 | private val configuration = Configuration.getInstance()
44 |
45 | private val titleLabel by lazy {
46 | JLabel(LanguagesFactory.createText(configuration.languageIndex).titleOne).also {
47 | it.isOpaque = true
48 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
49 | it.background = Colors.COLOR_BACKGROUND
50 | it.titleFont()
51 | }
52 | }
53 |
54 | private val modeLabel by lazy {
55 | JLabel(LanguagesFactory.createText(configuration.languageIndex).titleTwo).also {
56 | it.isOpaque = true
57 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
58 | it.background = Colors.COLOR_BACKGROUND
59 | it.titleFont()
60 | }
61 | }
62 |
63 | private val languageJComboBox by lazy {
64 | JComboBox().also {
65 | it.addItem("English")
66 | it.addItem("中文")
67 | }
68 | }
69 |
70 | private val language by lazy {
71 | JLabel(LanguagesFactory.createText(configuration.languageIndex).language).also {
72 | it.isOpaque = true
73 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
74 | it.background = Colors.COLOR_BACKGROUND
75 | it.preferredSize = Dimension(100, preferredSize.height)
76 | }
77 | }
78 |
79 | private val overrideCheckBox by lazy {
80 | JCheckBox(LanguagesFactory.createText(configuration.languageIndex).cover).also {
81 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
82 | it.background = Colors.COLOR_BACKGROUND
83 | it.secondTitleFont()
84 | it.preferredSize = Dimension(500, preferredSize.height)
85 | }
86 | }
87 |
88 | private val decimalCheckBox by lazy {
89 | JCheckBox(LanguagesFactory.createText(configuration.languageIndex).decimal).also {
90 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
91 | it.background = Colors.COLOR_BACKGROUND
92 | it.secondTitleFont()
93 | it.preferredSize = Dimension(800, preferredSize.height)
94 | }
95 | }
96 |
97 | private val decimalTextField by lazy {
98 | JTextField(configuration.decimalPlace.toString()).also {
99 | it.isOpaque = true
100 | it.border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
101 | it.preferredSize = Dimension(100, preferredSize.height)
102 | }
103 | }
104 |
105 | private val decimalLabel by lazy {
106 | JLabel(LanguagesFactory.createText(configuration.languageIndex).bit).also {
107 | it.isOpaque = true
108 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
109 | it.background = Colors.COLOR_BACKGROUND
110 | it.secondTitleFont()
111 | }
112 | }
113 |
114 | private val minWidthCheckBox by lazy {
115 | JCheckBox(LanguagesFactory.createText(configuration.languageIndex).minWidth).also {
116 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
117 | it.background = Colors.COLOR_BACKGROUND
118 | it.secondTitleFont()
119 | it.preferredSize = Dimension(800, preferredSize.height)
120 | }
121 | }
122 |
123 | private val minWidthTextField by lazy {
124 | JTextField(configuration.originWidth.toString()).also {
125 | it.isOpaque = true
126 | it.border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
127 | it.preferredSize = Dimension(100, preferredSize.height)
128 | }
129 | }
130 |
131 | private val minWidthLabel by lazy {
132 | JLabel(Constant.DP).also {
133 | it.isOpaque = true
134 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
135 | it.background = Colors.COLOR_BACKGROUND
136 | it.secondTitleFont()
137 | }
138 | }
139 |
140 | private val folderCheckBox by lazy {
141 | JCheckBox(LanguagesFactory.createText(configuration.languageIndex).folder).also {
142 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
143 | it.background = Colors.COLOR_BACKGROUND
144 | it.secondTitleFont()
145 | it.preferredSize = Dimension(800, preferredSize.height)
146 | }
147 | }
148 |
149 | private val folderTextField by lazy {
150 | JTextField(configuration.folderName).also {
151 | it.isOpaque = true
152 | it.border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
153 | it.preferredSize = Dimension(100, preferredSize.height)
154 | }
155 | }
156 |
157 | private val singleRadioButton by lazy {
158 | JRadioButton(LanguagesFactory.createText(configuration.languageIndex).single).also {
159 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
160 | it.background = Colors.COLOR_BACKGROUND
161 | it.secondTitleFont()
162 | it.preferredSize = Dimension(800, preferredSize.height)
163 | }
164 | }
165 |
166 | private val singleTextField by lazy {
167 | JTextField(configuration.single).also {
168 | it.isOpaque = true
169 | it.border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
170 | it.preferredSize = Dimension(100, preferredSize.height)
171 | }
172 | }
173 |
174 | private val singleLabel by lazy {
175 | JLabel(Constant.DP).also {
176 | it.isOpaque = true
177 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
178 | it.background = Colors.COLOR_BACKGROUND
179 | it.secondTitleFont()
180 | }
181 | }
182 |
183 | private val multiRadioButton by lazy {
184 | JRadioButton(LanguagesFactory.createText(configuration.languageIndex).multi).also {
185 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
186 | it.background = Colors.COLOR_BACKGROUND
187 | it.secondTitleFont()
188 | it.preferredSize = Dimension(150, preferredSize.height)
189 | }
190 | }
191 |
192 | private val multiTextField by lazy {
193 | JTextField(configuration.multi).also {
194 | it.isOpaque = true
195 | it.border = BorderFactory.createEmptyBorder(5, 10, 5, 10)
196 | it.preferredSize = Dimension(750, preferredSize.height)
197 | }
198 | }
199 |
200 | private val multiLabel by lazy {
201 | JLabel(Constant.DP).also {
202 | it.isOpaque = true
203 | it.border = BorderFactory.createEmptyBorder(10, 10, 10, 10)
204 | it.background = Colors.COLOR_BACKGROUND
205 | it.secondTitleFont()
206 | }
207 | }
208 |
209 | private val generateButton by lazy {
210 | JButton(LanguagesFactory.createText(configuration.languageIndex).genarate).also {
211 | it.border = BorderFactory.createEmptyBorder(10, 20, 10, 20)
212 | it.secondTitleFont()
213 | }
214 | }
215 |
216 | init {
217 | val root = JPanel()
218 | val migLayout = MigLayout("wrap")
219 | root.layout = migLayout
220 |
221 | root.add(titleLabel)
222 |
223 | val languagePanel = Panel()
224 | val languageBoxLayout = BoxLayout(languagePanel, BoxLayout.X_AXIS)
225 | languagePanel.background = Colors.COLOR_BACKGROUND
226 | languagePanel.foreground = Colors.COLOR_BACKGROUND
227 | languagePanel.layout = languageBoxLayout
228 | languagePanel.add(language)
229 | languagePanel.add(languageJComboBox)
230 | root.add(languagePanel)
231 |
232 | root.add(overrideCheckBox)
233 |
234 | val decimalPanel = Panel()
235 | val decimalBoxLayout = BoxLayout(decimalPanel, BoxLayout.X_AXIS)
236 | decimalPanel.background = Colors.COLOR_BACKGROUND
237 | decimalPanel.foreground = Colors.COLOR_BACKGROUND
238 | decimalPanel.layout = decimalBoxLayout
239 | decimalPanel.add(decimalCheckBox)
240 | decimalPanel.add(decimalTextField)
241 | decimalPanel.add(decimalLabel)
242 | root.add(decimalPanel)
243 |
244 | val minWidthPanel = Panel()
245 | val minWidthBoxLayout = BoxLayout(minWidthPanel, BoxLayout.X_AXIS)
246 | minWidthPanel.background = Colors.COLOR_BACKGROUND
247 | minWidthPanel.foreground = Colors.COLOR_BACKGROUND
248 | minWidthPanel.layout = minWidthBoxLayout
249 | minWidthPanel.add(minWidthCheckBox)
250 | minWidthPanel.add(minWidthTextField)
251 | minWidthPanel.add(minWidthLabel)
252 | root.add(minWidthPanel)
253 |
254 | val folderPanel = Panel()
255 | val folderBoxLayout = BoxLayout(folderPanel, BoxLayout.X_AXIS)
256 | folderPanel.background = Colors.COLOR_BACKGROUND
257 | folderPanel.foreground = Colors.COLOR_BACKGROUND
258 | folderPanel.layout = folderBoxLayout
259 | folderPanel.add(folderCheckBox)
260 | folderPanel.add(folderTextField)
261 | root.add(folderPanel)
262 |
263 | root.add(modeLabel)
264 |
265 | val singlePanel = Panel()
266 | val singleBoxLayout = BoxLayout(singlePanel, BoxLayout.X_AXIS)
267 | singlePanel.background = Colors.COLOR_BACKGROUND
268 | singlePanel.foreground = Colors.COLOR_BACKGROUND
269 | singlePanel.layout = singleBoxLayout
270 | singlePanel.add(singleRadioButton)
271 | singlePanel.add(singleTextField)
272 | singlePanel.add(singleLabel)
273 | root.add(singlePanel)
274 |
275 | val multiPanel = Panel()
276 | val multiBoxLayout = BoxLayout(multiPanel, BoxLayout.X_AXIS)
277 | multiPanel.background = Colors.COLOR_BACKGROUND
278 | multiPanel.foreground = Colors.COLOR_BACKGROUND
279 | multiPanel.layout = multiBoxLayout
280 | multiPanel.add(multiRadioButton)
281 | multiPanel.add(multiTextField)
282 | multiPanel.add(multiLabel)
283 | root.add(multiPanel)
284 |
285 | val buttonJPanel = JPanel(FlowLayout(FlowLayout.CENTER, 0, 20))
286 | buttonJPanel.add(generateButton)
287 | buttonJPanel.preferredSize = Dimension(900, preferredSize.height)
288 | root.add(buttonJPanel)
289 |
290 | add(root)
291 |
292 | pack()
293 | initSaveConfiguration()
294 | reStoreConfiguration()
295 |
296 | initClick()
297 | initJRadioButton()
298 | initCheckBox()
299 | initTextField()
300 | initData(currentFile, project)
301 | }
302 |
303 | private fun initCheckBox() {
304 | overrideCheckBox.addChangeListener { e: ChangeEvent ->
305 | val jCheckBox = e.source as JCheckBox
306 | configuration.isOverride = jCheckBox.isSelected
307 | }
308 | decimalCheckBox.addChangeListener { e: ChangeEvent ->
309 | val jCheckBox = e.source as JCheckBox
310 | configuration.isKeepDecimal = jCheckBox.isSelected
311 | }
312 | minWidthCheckBox.addChangeListener { e: ChangeEvent ->
313 | val jCheckBox = e.source as JCheckBox
314 | configuration.isMinWidth = jCheckBox.isSelected
315 | }
316 | folderCheckBox.addChangeListener { e: ChangeEvent ->
317 | val jCheckBox = e.source as JCheckBox
318 | configuration.isReName = jCheckBox.isSelected
319 | }
320 | }
321 |
322 | private fun initData(currentFile: VirtualFile, project: Project) {
323 | generateButton.addActionListener {
324 | var decimal = 0
325 | if (decimalTextField.text.isNullOrBlank()) {
326 | showErrorMessage(LanguagesFactory.createText(configuration.languageIndex).tipsInputEmpty)
327 | return@addActionListener
328 | } else {
329 | decimal = if (configuration.isKeepDecimal) decimalTextField.text.toInt() else 0
330 | }
331 |
332 | var folderName = if (configuration.isReName) {
333 | folderTextField.text
334 | } else {
335 | Constant.LAYOUT_FOLDER_NAME
336 | }
337 |
338 | var minWidth = 0f
339 | when {
340 | minWidthTextField.text.isNullOrBlank() -> {
341 | showErrorMessage(LanguagesFactory.createText(configuration.languageIndex).tipsInputEmpty)
342 | return@addActionListener
343 | }
344 |
345 | minWidthTextField.text == "0" -> {
346 | showErrorMessage(LanguagesFactory.createText(configuration.languageIndex).tipsInputZero)
347 | return@addActionListener
348 | }
349 |
350 | else -> {
351 | minWidth = if (configuration.isMinWidth) minWidthTextField.text.toFloat() else 360f
352 | }
353 | }
354 |
355 | if (multiTextField.text.isNullOrBlank()) {
356 | showErrorMessage(LanguagesFactory.createText(configuration.languageIndex).tipsInputEmpty)
357 | return@addActionListener
358 | }
359 | val split = multiTextField.text.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
360 | val targets = split.map {
361 | if (it.trim() == "0") {
362 | showErrorMessage(LanguagesFactory.createText(configuration.languageIndex).tipsInputZero)
363 | return@addActionListener
364 | }
365 | it.toFloat()
366 | }
367 |
368 | val target: Float
369 | if (singleTextField.text.isNullOrBlank()) {
370 | showErrorMessage(LanguagesFactory.createText(configuration.languageIndex).tipsInputEmpty)
371 | return@addActionListener
372 | } else if (singleTextField.text == "0") {
373 | showErrorMessage(LanguagesFactory.createText(configuration.languageIndex).tipsInputZero)
374 | return@addActionListener
375 | } else {
376 | target = singleTextField.text.toFloat()
377 | }
378 | try {
379 | when {
380 | configuration.isSingle -> {
381 | generateSingle(
382 | currentFile,
383 | configuration.isOverride,
384 | decimal,
385 | minWidth,
386 | folderName,
387 | target
388 | )
389 | }
390 |
391 | else -> {
392 | generateMulti(
393 | currentFile,
394 | configuration.isOverride,
395 | decimal,
396 | minWidth,
397 | folderName,
398 | targets
399 | )
400 | }
401 | }
402 | VirtualFileManager.getInstance().syncRefresh()
403 | showMessage(LanguagesFactory.createText(configuration.languageIndex).tipsGenerateSuccess)
404 | } catch (e: Exception) {
405 | showErrorMessage(e.message ?: LanguagesFactory.createText(configuration.languageIndex).tipsGenerateFail)
406 | }
407 | currentFile.refresh(false,true)
408 | dispose()
409 | }
410 | }
411 |
412 | private fun generateMulti(
413 | currentFile: VirtualFile,
414 | isOverride: Boolean,
415 | decimal: Int,
416 | originDimens: Float,
417 | folderName: String,
418 | targetDimens: List
419 | ) {
420 | for (target in targetDimens) {
421 | generateSingle(currentFile, isOverride, decimal, originDimens, folderName, target)
422 | }
423 | }
424 |
425 | @Throws(Exception::class)
426 | private fun generateSingle(
427 | currentFile: VirtualFile,
428 | isOverride: Boolean,
429 | decimal: Int,
430 | originDimens: Float,
431 | folderName: String,
432 | targetDimens: Float
433 | ) {
434 | val factory = DocumentBuilderFactory.newInstance()
435 | val builder = factory.newDocumentBuilder()
436 | val file = File(
437 | currentFile.canonicalPath
438 | ?: throw Exception(LanguagesFactory.createText(configuration.languageIndex).exceptionOfFileError)
439 | )
440 | val document = builder.parse(file)
441 | val scale = originDimens / targetDimens
442 | println("scale: $scale")
443 | transformerDimens(document.getElementsByTagName("dimen"), decimal, scale)
444 | generateDimens(
445 | document, currentFile.parent.parent.canonicalPath ?: throw Exception(
446 | LanguagesFactory.createText(
447 | configuration.languageIndex
448 | ).exceptionOfFileError
449 | ), "values-" + folderName + targetDimens.toInt() + "dp", isOverride
450 | )
451 | }
452 |
453 | private fun transformerDimens(nodeList: NodeList, decimal: Int, scale: Float) {
454 | for (i in 0 until nodeList.length) {
455 | val item = nodeList.item(i) as Element
456 | println("Attribute name: ${item.nodeName}")
457 | println("Attribute value: ${item.nodeValue}")
458 | when {
459 | item.textContent.endsWith("dip") -> {
460 | val itemValue = item.textContent.substring(0, item.textContent.length - 3).toFloat()
461 | item.textContent = targetDimension(itemValue, decimal, scale) + "dp"
462 | }
463 |
464 | item.textContent.endsWith("dp") -> {
465 | val itemValue = item.textContent.substring(0, item.textContent.length - 2).toFloat()
466 | item.textContent = targetDimension(itemValue, decimal, scale) + "dp"
467 | }
468 |
469 | item.textContent.endsWith("sp") -> {
470 | val itemValue = item.textContent.substring(0, item.textContent.length - 2).toFloat()
471 | item.textContent = targetDimension(itemValue, decimal, scale) + "sp"
472 | }
473 |
474 | item.textContent.endsWith("px") -> {
475 | //todo 后续版本完善
476 | }
477 | }
478 | println("textContent: ${item.textContent}")
479 | }
480 | }
481 |
482 | @Throws(Exception::class)
483 | private fun generateDimens(document: Document, parentPath: String, folderName: String, isOverride: Boolean) {
484 | val folderPath = parentPath + File.separator + folderName
485 | val folderFile = File(folderPath)
486 | if (!folderFile.exists() && !folderFile.mkdir()) {
487 | throw Exception(
488 | LanguagesFactory.createText(
489 | configuration.languageIndex
490 | ).tipsCreateFileFailed
491 | )
492 | }
493 | val dimensFile = File(folderPath + File.separator + Constant.DIMENS_XML_NAME)
494 | if (!isOverride && dimensFile.exists()) {
495 | throw Exception(
496 | String.format(
497 | LanguagesFactory.createText(
498 | configuration.languageIndex
499 | ).tipsDimensExists, folderName
500 | )
501 | )
502 | }
503 | if (!dimensFile.delete()) {
504 | println("删除文件失败失败:" + dimensFile.name)
505 | }
506 | val transformerFactory = TransformerFactory.newInstance()
507 | val transformer = transformerFactory.newTransformer()
508 | val source = DOMSource(document)
509 | val result = StreamResult(dimensFile)
510 | transformer.transform(source, result)
511 | }
512 |
513 | private fun initTextField() {
514 | decimalTextField.document.addDocumentListener(object : DocumentListener {
515 | override fun insertUpdate(e: DocumentEvent) {
516 | configuration.decimalPlace = decimalTextField.text.toInt()
517 | }
518 |
519 | override fun removeUpdate(e: DocumentEvent) {
520 | configuration.decimalPlace = decimalTextField.text.toInt()
521 | }
522 |
523 | override fun changedUpdate(e: DocumentEvent) {}
524 | })
525 | minWidthTextField.document.addDocumentListener(object : DocumentListener {
526 | override fun insertUpdate(e: DocumentEvent) {
527 | configuration.originWidth = minWidthTextField.text.toFloat()
528 | }
529 |
530 | override fun removeUpdate(e: DocumentEvent) {
531 | configuration.originWidth = minWidthTextField.text.toFloat()
532 | }
533 |
534 | override fun changedUpdate(e: DocumentEvent) {}
535 | })
536 | folderTextField.document.addDocumentListener(object : DocumentListener {
537 | override fun insertUpdate(e: DocumentEvent) {
538 | configuration.folderName = folderTextField.text.toString()
539 | }
540 |
541 | override fun removeUpdate(e: DocumentEvent) {
542 | configuration.folderName = folderTextField.text.toString()
543 | }
544 |
545 | override fun changedUpdate(e: DocumentEvent) {}
546 | })
547 | singleTextField.document.addDocumentListener(object : DocumentListener {
548 | override fun insertUpdate(e: DocumentEvent) {
549 | configuration.single = singleTextField.text.toString()
550 | }
551 |
552 | override fun removeUpdate(e: DocumentEvent) {
553 | configuration.single = singleTextField.text.toString()
554 | }
555 |
556 | override fun changedUpdate(e: DocumentEvent) {}
557 | })
558 | multiTextField.document.addDocumentListener(object : DocumentListener {
559 | override fun insertUpdate(e: DocumentEvent) {
560 | configuration.multi = multiTextField.text.toString()
561 | }
562 |
563 | override fun removeUpdate(e: DocumentEvent) {
564 | configuration.multi = multiTextField.text.toString()
565 | }
566 |
567 | override fun changedUpdate(e: DocumentEvent) {}
568 | })
569 | }
570 |
571 | private fun initClick() {
572 | languageJComboBox.addItemListener { e: ItemEvent ->
573 | if (e.stateChange == ItemEvent.SELECTED) {
574 | configuration.languageIndex = languageJComboBox.selectedIndex
575 | toggleLanguage()
576 | }
577 | }
578 | }
579 |
580 | private fun toggleLanguage() {
581 | title = LanguagesFactory.createText(configuration.languageIndex).titleOne
582 | titleLabel.text = LanguagesFactory.createText(configuration.languageIndex).titleOne
583 | modeLabel.text = LanguagesFactory.createText(configuration.languageIndex).titleTwo
584 | language.text = LanguagesFactory.createText(configuration.languageIndex).language
585 | overrideCheckBox.text = LanguagesFactory.createText(configuration.languageIndex).cover
586 | decimalCheckBox.text = LanguagesFactory.createText(configuration.languageIndex).decimal
587 | decimalLabel.text = LanguagesFactory.createText(configuration.languageIndex).bit
588 | minWidthCheckBox.text = LanguagesFactory.createText(configuration.languageIndex).minWidth
589 | folderCheckBox.text = LanguagesFactory.createText(configuration.languageIndex).folder
590 | singleRadioButton.text = LanguagesFactory.createText(configuration.languageIndex).single
591 | multiRadioButton.text = LanguagesFactory.createText(configuration.languageIndex).multi
592 | generateButton.text = LanguagesFactory.createText(configuration.languageIndex).genarate
593 | }
594 |
595 | private fun initJRadioButton() {
596 | val bg = ButtonGroup()
597 | bg.add(singleRadioButton)
598 | bg.add(multiRadioButton)
599 | singleRadioButton.isSelected = configuration.isSingle
600 | multiRadioButton.isSelected = !configuration.isSingle
601 | singleRadioButton.addChangeListener {
602 | configuration.isSingle = singleRadioButton.isSelected
603 | }
604 | multiRadioButton.addChangeListener {
605 | configuration.isSingle = !multiRadioButton.isSelected
606 | }
607 | }
608 |
609 | private fun initSaveConfiguration() {
610 | addWindowStateListener { configuration.state }
611 | }
612 |
613 | private fun reStoreConfiguration() {
614 | languageJComboBox.selectedIndex = configuration.languageIndex
615 | overrideCheckBox.isSelected = configuration.isOverride
616 | decimalCheckBox.isSelected = configuration.isKeepDecimal
617 | minWidthCheckBox.isSelected = configuration.isMinWidth
618 | folderCheckBox.isSelected = configuration.isReName
619 | decimalTextField.text = configuration.decimalPlace.toString()
620 | minWidthTextField.text = configuration.originWidth.toString()
621 | folderTextField.text = configuration.folderName
622 | singleTextField.text = configuration.single
623 | multiTextField.text = configuration.multi
624 | toggleLanguage()
625 | }
626 |
627 | fun showFrame() {
628 | title = LanguagesFactory.createText(configuration.languageIndex).titleOne
629 | setSize(980, 600)
630 | setLocationRelativeTo(null)
631 | isVisible = true
632 | }
633 | }
--------------------------------------------------------------------------------