Skip to content

Commit 63e0464

Browse files
committed
feat: add tools
1 parent 2eb72c0 commit 63e0464

12 files changed

Lines changed: 856 additions & 0 deletions
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.dengzii.plugin.template.tools
2+
3+
object EditorHintUtils {
4+
5+
fun showError() {
6+
7+
}
8+
9+
fun showQuestion() {
10+
11+
}
12+
13+
fun showInfo() {
14+
15+
}
16+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.dengzii.plugin.template.tools
2+
3+
import com.intellij.openapi.application.ApplicationManager
4+
5+
fun invokeLater(action: () -> Unit) {
6+
ApplicationManager.getApplication().invokeLater(action)
7+
}
Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
package com.dengzii.plugin.template.tools
2+
3+
import com.intellij.notification.*
4+
import com.intellij.openapi.Disposable
5+
import com.intellij.openapi.application.ApplicationManager
6+
import com.intellij.openapi.project.Project
7+
import com.intellij.openapi.util.Disposer
8+
import com.intellij.util.Alarm
9+
10+
/**
11+
* <pre>
12+
* author : dengzi
13+
* e-mail : dengzii@foxmail.com
14+
* github : https://github.com/dengzii
15+
* time : 2020/11/18
16+
* desc : Utils about Notification.
17+
</pre> *
18+
*/
19+
object NotificationUtils {
20+
21+
var defaultTitle = "Notification"
22+
23+
var balloonGroup = NotificationGroup("Untitled_Notification", NotificationDisplayType.BALLOON, true)
24+
var stickyGroup = NotificationGroup("Untitled_Notification", NotificationDisplayType.STICKY_BALLOON, true)
25+
26+
fun getInfo(msg: String, title: String = defaultTitle): Notification {
27+
return balloonGroup.createNotification(NotificationType.INFORMATION).apply {
28+
setTitle(title)
29+
setContent(msg)
30+
}
31+
}
32+
33+
fun getError(msg: String, title: String = defaultTitle): Notification {
34+
return stickyGroup.createNotification(NotificationType.ERROR).apply {
35+
setTitle(title)
36+
setContent(msg)
37+
}
38+
}
39+
40+
fun getWarning(msg: String, title: String = defaultTitle): Notification {
41+
return balloonGroup.createNotification(NotificationType.WARNING).apply {
42+
setTitle(title)
43+
setContent(msg)
44+
}
45+
}
46+
47+
fun showInfo(msg: String, title: String = defaultTitle): Notification {
48+
return getInfo(msg, title).show()
49+
}
50+
51+
fun showError(msg: String, title: String = defaultTitle): Notification {
52+
return getError(msg, title).show()
53+
}
54+
55+
fun showWarning(msg: String, title: String = defaultTitle): Notification {
56+
return getWarning(msg, title).show()
57+
}
58+
59+
fun Notification.show(expireMillis: Long? = null, project: Project? = null): Notification {
60+
Notifications.Bus.notify(this, project)
61+
if (expireMillis != null) {
62+
val alarm = Alarm(((project ?: ApplicationManager.getApplication()) as Disposable))
63+
alarm.addRequest({
64+
expire()
65+
Disposer.dispose(alarm)
66+
}, expireMillis)
67+
}
68+
return this
69+
}
70+
}
Lines changed: 164 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,164 @@
1+
package com.dengzii.plugin.template.tools
2+
3+
import com.dengzii.plugin.template.tools.PersistentConfig.ObjectSerializer
4+
import com.google.gson.Gson
5+
import com.google.gson.JsonParseException
6+
import com.intellij.ide.util.PropertiesComponent
7+
import com.intellij.openapi.project.Project
8+
import kotlin.properties.ReadWriteProperty
9+
import kotlin.reflect.KClass
10+
import kotlin.reflect.KProperty
11+
12+
/**
13+
* Make data persistence more easy.
14+
*
15+
* Delegate field's getter/setter to [PropertiesComponent], the complex type will serialize/deserialize
16+
* use gson by default, you can custom [ObjectSerializer] instead it.
17+
*
18+
* @param propertiesComp The [PropertiesComponent]
19+
* @param project The project use for obtain [PropertiesComponent], ignored when propertiesComp is non-null.
20+
* @param keySuffix The key suffix use for persist.
21+
* @param objectSerializer The serialize/deserialize factory for complex type.
22+
*
23+
* @author https://github.com/dengzii
24+
*/
25+
open class PersistentConfig(
26+
propertiesComp: PropertiesComponent? = null,
27+
project: Project? = null,
28+
private val keySuffix: String = "KEY",
29+
private val objectSerializer: ObjectSerializer = JsonObjectSerializer()
30+
) {
31+
32+
private val propertiesComponent: PropertiesComponent = propertiesComp ?: if (project == null) {
33+
PropertiesComponent.getInstance()
34+
} else {
35+
PropertiesComponent.getInstance(project)
36+
}
37+
38+
/**
39+
* Return the delegate for field need to persist.
40+
*
41+
* @param defaultValue The default when load value failed.
42+
* @param keyName The key name use for persist.
43+
*
44+
* @return [PropertyDelegate]
45+
*/
46+
inline fun <reified T> persistentProperty(defaultValue: T, keyName: String? = null): PropertyDelegate<T> {
47+
return when (defaultValue) {
48+
is Int?,
49+
is Boolean?,
50+
is Float?,
51+
is String?,
52+
is Array<*>? -> {
53+
PropertyDelegate(defaultValue, T::class, keyName)
54+
}
55+
else -> PropertyDelegate(defaultValue, T::class, keyName)
56+
}
57+
}
58+
59+
/**
60+
* The interface defines how to serializer/deserializer the object not primitive type.
61+
*/
62+
interface ObjectSerializer {
63+
fun serialize(obj: Any, clazz: KClass<*>): String
64+
fun deserialize(str: String, clazz: KClass<*>): Any
65+
}
66+
67+
/**
68+
* The json serializer/deserializer use gson.
69+
*/
70+
class JsonObjectSerializer : ObjectSerializer {
71+
72+
private val gson: Gson = Gson().newBuilder()
73+
.setLenient()
74+
.serializeNulls()
75+
.create()
76+
77+
@Throws(JsonParseException::class)
78+
override fun serialize(obj: Any, clazz: KClass<*>): String {
79+
return gson.toJson(obj)
80+
}
81+
82+
@Throws(JsonParseException::class)
83+
override fun deserialize(str: String, clazz: KClass<*>): Any {
84+
return gson.fromJson(str, clazz.java)
85+
}
86+
}
87+
88+
/**
89+
* This class is a delegate class for a field need to persist.
90+
*
91+
* @param default The default when read property failed, the following situation will return [default]:
92+
* 1, The key does not exist.
93+
* 2, Read value successful but serialize/deserialize failed.
94+
* 3, An exception was caught.
95+
* @param clazz The KClass of field.
96+
* @param keyName The key name, the field name is used when null.
97+
*/
98+
inner class PropertyDelegate<T : Any?>
99+
constructor(
100+
private val default: T,
101+
private val clazz: KClass<*>,
102+
private val keyName: String? = null
103+
) : ReadWriteProperty<PersistentConfig, T?> {
104+
105+
@Suppress("UNCHECKED_CAST")
106+
override fun getValue(thisRef: PersistentConfig, property: KProperty<*>): T? {
107+
val keyName = getKeyName(property)
108+
return try {
109+
with(thisRef.propertiesComponent) {
110+
when (clazz) {
111+
Int::class -> getInt(keyName, default as Int)
112+
Boolean::class -> getBoolean(keyName, default as Boolean)
113+
String::class -> getValue(keyName, default as String)
114+
Float::class -> getFloat(keyName, default as Float)
115+
Array<String>::class -> getValues(keyName)
116+
// deserialize to object
117+
else -> {
118+
val v = getValue(keyName)
119+
if (v != null) {
120+
objectSerializer.deserialize(v, clazz)
121+
} else {
122+
default
123+
}
124+
}
125+
}
126+
} as T
127+
} catch (ignore: TypeCastException) {
128+
default
129+
} catch (e: Throwable) {
130+
e.printStackTrace()
131+
default
132+
}
133+
}
134+
135+
override fun setValue(thisRef: PersistentConfig, property: KProperty<*>, value: T?) {
136+
val keyName = getKeyName(property)
137+
with(thisRef.propertiesComponent) {
138+
when (value) {
139+
is Int -> setValue(keyName, value, default as Int)
140+
is Boolean -> setValue(keyName, value, default as Boolean)
141+
is String -> setValue(keyName, value, default as String)
142+
is Float -> setValue(keyName, value, default as Float)
143+
is Array<*> -> {
144+
val arr = value.filterIsInstance<String>().toTypedArray()
145+
setValues(keyName, arr)
146+
}
147+
null -> unsetValue(keyName)
148+
else -> {
149+
try {
150+
val serialized = objectSerializer.serialize(value, clazz)
151+
setValue(keyName, serialized)
152+
} catch (e: Throwable) {
153+
throw RuntimeException("Type unsupported.", e)
154+
}
155+
}
156+
}
157+
}
158+
}
159+
160+
private fun getKeyName(property: KProperty<*>): String {
161+
return "${keySuffix}_${keyName ?: property.name}"
162+
}
163+
}
164+
}
Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,90 @@
1+
package com.dengzii.plugin.template.tools.ui
2+
3+
import com.intellij.ui.components.JBLabel
4+
import com.intellij.ui.components.JBTextField
5+
import java.awt.Component
6+
7+
8+
/**
9+
* The model of the column of [JTable].
10+
*
11+
* @author https://github.com/dengzii
12+
*/
13+
open class ColumnInfo<Item>(val colName: String) {
14+
15+
private var editable: Boolean = false
16+
17+
open val columnClass: Class<*> get() = String::class.java
18+
19+
open var columnWidth: Int? = null
20+
21+
constructor(colName: String, editable: Boolean) : this(colName) {
22+
this.editable = editable
23+
}
24+
25+
companion object {
26+
fun of(vararg columns: String): List<ColumnInfo<Any>> {
27+
return columns.map { ColumnInfo(it) }
28+
}
29+
}
30+
31+
/**
32+
* Return the value of column when edit finish, if this column is editable.
33+
*
34+
* @param component The edit component.
35+
* @param oldValue The old value before edit.
36+
* @return A new value.
37+
*/
38+
open fun getEditorValue(component: Component, oldValue: Item?, row: Int, col: Int): Item? {
39+
return null
40+
}
41+
42+
/**
43+
* Whether this column editable.
44+
* @param item The item value.
45+
* @return True is editable, otherwise not.
46+
*/
47+
open fun isCellEditable(item: Item?): Boolean {
48+
return editable
49+
}
50+
51+
/**
52+
* Return a [Component] use for display item value.
53+
* @param item The item value.
54+
* @return The component.
55+
*/
56+
open fun getRendererComponent(item: Item?, row: Int, col: Int): Component {
57+
return JBLabel(item?.toString().orEmpty())
58+
}
59+
60+
/**
61+
* Return a [Component] use for edit this column.
62+
*
63+
* Working just when [isCellEditable] returns true.
64+
*
65+
* @param item The item value.
66+
* @return The component.
67+
*/
68+
open fun getEditComponent(item: Item?, row: Int, col: Int): Component {
69+
return JBTextField(item?.toString().orEmpty())
70+
}
71+
72+
override fun equals(other: Any?): Boolean {
73+
return if (this === other) {
74+
true
75+
} else if (other != null && this.javaClass == other.javaClass) {
76+
val that = other as ColumnInfo<*>
77+
colName == that.colName
78+
} else {
79+
false
80+
}
81+
}
82+
83+
override fun hashCode(): Int {
84+
return colName.hashCode()
85+
}
86+
87+
override fun toString(): String {
88+
return colName
89+
}
90+
}

0 commit comments

Comments
 (0)