Skip to content

Commit

Permalink
WEB-51321: styled-components memory leak
Browse files Browse the repository at this point in the history
GitOrigin-RevId: a8b79bffc71d3763f8aec2d29c3ca2fa896c6db2
  • Loading branch information
vepanimas authored and intellij-monorepo-bot committed Jun 15, 2021
1 parent 7478e6a commit 2c6a4cd
Showing 1 changed file with 112 additions and 106 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -19,139 +19,145 @@ import com.intellij.util.ui.EditableModel
import com.intellij.util.ui.ItemRemovable
import com.intellij.util.ui.table.*
import java.awt.BorderLayout
import java.util.*
import javax.swing.JComponent
import javax.swing.JPanel
import javax.swing.JTable
import javax.swing.table.AbstractTableModel

class StyledComponentsConfigurable(private val project: Project) : SearchableConfigurable {
private val myConfiguration = CustomInjectionsConfiguration.instance(project)
private val tagsModel = TagsModel()
private val disposable = Disposer.newDisposable()
private val myTagPrefixesField = object : JBListTable(JBTable(tagsModel), disposable) {
override fun getRowRenderer(p0: Int): JBTableRowRenderer = object : EditorTextFieldJBTableRowRenderer(project, PlainTextFileType.INSTANCE, disposable) {
override fun getText(p0: JTable?, index: Int): String = tagsModel.myTags[index]
}
private val myConfiguration = CustomInjectionsConfiguration.instance(project)
private val tagsModel = TagsModel()
private val disposable = Disposer.newDisposable()

private fun createPrefixesField() = object : JBListTable(JBTable(tagsModel), disposable) {
override fun getRowRenderer(p0: Int): JBTableRowRenderer = object : EditorTextFieldJBTableRowRenderer(project,
PlainTextFileType.INSTANCE,
disposable) {
override fun getText(p0: JTable?, index: Int): String = tagsModel.myTags[index]
}

override fun getRowEditor(p0: Int): JBTableRowEditor = object : JBTableRowEditor() {
override fun getValue(): JBTableRow = JBTableRow { (getComponent(0) as EditorTextField).text }
override fun prepareEditor(p0: JTable?, p1: Int) {
layout = BorderLayout()
val editor = EditorTextField(tagsModel.myTags[p1])
editor.addDocumentListener(RowEditorChangeListener(0))
val validator = ComponentValidator(disposable)
editor.addDocumentListener(object : DocumentListener {
override fun documentChanged(event: DocumentEvent) {
validator.updateInfo(getErrorText(editor.text)?.let { ValidationInfo(it, editor) })
}
})
add(editor, BorderLayout.NORTH)
validator.updateInfo(getErrorText(editor.text)?.let { ValidationInfo(it, editor) })
}

override fun getFocusableComponents(): Array<JComponent> = arrayOf(preferredFocusedComponent)
override fun getPreferredFocusedComponent(): JComponent = getComponent(0) as JComponent

fun getErrorText(value: String?): String? {
val trimmed = value?.trim() ?: ""
val names = trimmed.split(".")
if (trimmed.isBlank() || names.isEmpty()) {
return "Value is empty"
}
return names.foldIndexed<String, String?>(null) { index, previous, string ->
if (previous != null) {
previous
} else if (index == 0 && !LanguageNamesValidation.INSTANCE.forLanguage(JavascriptLanguage.INSTANCE).isIdentifier(string, project)) {
"'$string' is not a valid JavaScript identifier"
} else if (!JSNamesValidation.isIdentifierName(string)) {
"'$string' is not a valid property name"
} else {
null
}
}
}
override fun getRowEditor(p0: Int): JBTableRowEditor = object : JBTableRowEditor() {
override fun getValue(): JBTableRow = JBTableRow { (getComponent(0) as EditorTextField).text }
override fun prepareEditor(p0: JTable?, p1: Int) {
layout = BorderLayout()
val editor = EditorTextField(tagsModel.myTags[p1])
editor.addDocumentListener(RowEditorChangeListener(0))
val validator = ComponentValidator(disposable)
editor.addDocumentListener(object : DocumentListener {
override fun documentChanged(event: DocumentEvent) {
validator.updateInfo(getErrorText(editor.text)?.let { ValidationInfo(it, editor) })
}
})
add(editor, BorderLayout.NORTH)
validator.updateInfo(getErrorText(editor.text)?.let { ValidationInfo(it, editor) })
}

override fun getFocusableComponents(): Array<JComponent> = arrayOf(preferredFocusedComponent)
override fun getPreferredFocusedComponent(): JComponent = getComponent(0) as JComponent

fun getErrorText(value: String?): String? {
val trimmed = value?.trim() ?: ""
val names = trimmed.split(".")
if (trimmed.isBlank() || names.isEmpty()) {
return "Value is empty"
}
return names.foldIndexed<String, String?>(null) { index, previous, string ->
if (previous != null) {
previous
}
else if (index == 0 && !LanguageNamesValidation.INSTANCE.forLanguage(JavascriptLanguage.INSTANCE).isIdentifier(string, project)) {
"'$string' is not a valid JavaScript identifier"
}
else if (!JSNamesValidation.isIdentifierName(string)) {
"'$string' is not a valid property name"
}
else {
null
}
}
}
}
}

override fun isModified(): Boolean {
return !getPrefixesFromUi().contentEquals((myConfiguration.getTagPrefixes()))
}
override fun isModified(): Boolean {
return !getPrefixesFromUi().contentEquals((myConfiguration.getTagPrefixes()))
}

private fun getPrefixesFromUi(): Array<String> {
return tagsModel.myTags.toTypedArray()
}
private fun getPrefixesFromUi(): Array<String> {
return tagsModel.myTags.toTypedArray()
}

override fun getId(): String {
return "styled-components"
}
override fun getId(): String {
return "styled-components"
}

override fun getDisplayName(): String {
return StyledComponentsBundle.message("styled.components.configurable.title")
}
override fun getDisplayName(): String {
return StyledComponentsBundle.message("styled.components.configurable.title")
}

override fun apply() {
myConfiguration.setTagPrefixes(getPrefixesFromUi())
com.intellij.util.FileContentUtil.reparseFiles(project, emptyList(), true)
}
override fun apply() {
myConfiguration.setTagPrefixes(getPrefixesFromUi())
com.intellij.util.FileContentUtil.reparseFiles(project, emptyList(), true)
}

override fun reset() {
tagsModel.setTags(myConfiguration.getTagPrefixes())
}
override fun reset() {
tagsModel.setTags(myConfiguration.getTagPrefixes())
}

override fun createComponent(): JComponent {
val table = ToolbarDecorator.createDecorator(myTagPrefixesField.table).disableUpDownActions().createPanel()
val component = LabeledComponent.create(
table, StyledComponentsBundle.message("styled.components.configurable.label.tag.prefixes"))
override fun createComponent(): JComponent {
val tagPrefixesField = createPrefixesField()
val table = ToolbarDecorator.createDecorator(tagPrefixesField.table).disableUpDownActions().createPanel()
val component = LabeledComponent.create(
table, StyledComponentsBundle.message("styled.components.configurable.label.tag.prefixes"))

val panel = JPanel(BorderLayout())
panel.add(component, BorderLayout.NORTH)
return panel
}
val panel = JPanel(BorderLayout())
panel.add(component, BorderLayout.NORTH)
return panel
}

override fun disposeUIResources() {
Disposer.dispose(disposable)
}
override fun disposeUIResources() {
Disposer.dispose(disposable)
}

private class TagsModel : AbstractTableModel(), ItemRemovable, EditableModel {
var myTags: MutableList<String> = ArrayList()
private class TagsModel : AbstractTableModel(), ItemRemovable, EditableModel {
var myTags: MutableList<String> = ArrayList()

override fun getRowCount(): Int {
return myTags.size
}
override fun getRowCount(): Int {
return myTags.size
}

override fun getColumnCount(): Int {
return 1
}
override fun getColumnCount(): Int {
return 1
}

override fun getValueAt(row: Int, column: Int): Any? = myTags[row]
override fun getValueAt(row: Int, column: Int): Any? = myTags[row]

override fun setValueAt(o: Any?, row: Int, column: Int) {
myTags[row] = o as String
fireTableCellUpdated(row, column)
}
override fun setValueAt(o: Any?, row: Int, column: Int) {
myTags[row] = o as String
fireTableCellUpdated(row, column)
}

override fun addRow() {
myTags.add("")
val row = myTags.size - 1
fireTableRowsInserted(row, row)
}
override fun addRow() {
myTags.add("")
val row = myTags.size - 1
fireTableRowsInserted(row, row)
}

override fun exchangeRows(oldIndex: Int, newIndex: Int) {}
override fun exchangeRows(oldIndex: Int, newIndex: Int) {}

override fun canExchangeRows(oldIndex: Int, newIndex: Int): Boolean {
return false
}
override fun canExchangeRows(oldIndex: Int, newIndex: Int): Boolean {
return false
}

override fun removeRow(idx: Int) {
myTags.removeAt(idx)
fireTableRowsDeleted(idx, idx)
}
override fun removeRow(idx: Int) {
myTags.removeAt(idx)
fireTableRowsDeleted(idx, idx)
}

fun setTags(tags: Array<String>) {
myTags.clear()
myTags.addAll(tags)
fireTableStructureChanged()
}
fun setTags(tags: Array<String>) {
myTags.clear()
myTags.addAll(tags)
fireTableStructureChanged()
}
}
}

0 comments on commit 2c6a4cd

Please sign in to comment.