Skip to content

Commit db829df

Browse files
authored
Add vertical scrollbar when needed (#52)
1 parent c60a456 commit db829df

10 files changed

Lines changed: 97 additions & 17 deletions

File tree

gradle.properties

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ pluginGroup = no.spk.fiskeoye.plugin
44
pluginName = fiskeoye-plugin
55
pluginRepositoryUrl = https://github.com/statens-pensjonskasse/fiskeoye-plugin
66
# SemVer format -> https://semver.org
7-
pluginVersion = 0.0.3
7+
pluginVersion = 0.0.4
88

99
# Supported build number ranges and IntelliJ Platform versions -> https://plugins.jetbrains.com/docs/intellij/build-number-ranges.html
1010
pluginSinceBuild = 233

images/fiskeoye_4.png

-1.94 KB
Loading

src/main/kotlin/no/spk/fiskeoye/plugin/FiskeoyeToolWindowFactory.kt

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -24,15 +24,13 @@ internal class FiskeoyeToolWindowFactory : ToolWindowFactory, DumbAware {
2424
val contentFactory: ContentFactory = ContentFactory.getInstance()
2525
val toolWindowEx = toolWindow as ToolWindowEx
2626

27-
val fileContentPanel = FileContentPanel()
28-
val fileContent = contentFactory.createContent(fileContentPanel, "File Content", false).apply {
27+
val fileContent = contentFactory.createContent(FileContentPanel(), "File Content", false).apply {
2928
isCloseable = false
3029
putUserData(CONTENT_TYPE_KEY, ContentType.FILE_CONTENT)
3130
}
3231
toolWindowEx.contentManager.addContent(fileContent)
3332

34-
val filenamePanel = FilenamePanel()
35-
val filename = contentFactory.createContent(filenamePanel, "File Name", false).apply {
33+
val filename = contentFactory.createContent(FilenamePanel(), "File Name", false).apply {
3634
isCloseable = false
3735
putUserData(CONTENT_TYPE_KEY, ContentType.FILENAME)
3836
}
@@ -48,9 +46,7 @@ internal class FiskeoyeToolWindowFactory : ToolWindowFactory, DumbAware {
4846
}
4947
}
5048
})
51-
52-
val newTabActionGroup = buildNewTabActionGroup(toolWindow, contentFactory)
53-
toolWindowEx.setTabActions(newTabActionGroup)
49+
toolWindowEx.setTabActions(buildNewTabActionGroup(toolWindow, contentFactory))
5450
}
5551

5652
private fun buildNewTabActionGroup(toolWindow: ToolWindow, contentFactory: ContentFactory): DefaultActionGroup {

src/main/kotlin/no/spk/fiskeoye/plugin/listeners/button/FileContentSearchListener.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,13 +10,17 @@ import no.spk.fiskeoye.plugin.util.addMessage
1010
import no.spk.fiskeoye.plugin.util.clear
1111
import no.spk.fiskeoye.plugin.util.getDefaultModel
1212
import no.spk.fiskeoye.plugin.util.getHeaderText
13+
import no.spk.fiskeoye.plugin.util.getHtml
1314
import no.spk.fiskeoye.plugin.util.getInvalidString
1415
import no.spk.fiskeoye.plugin.util.getProject
1516
import no.spk.fiskeoye.plugin.util.getService
1617
import no.spk.fiskeoye.plugin.util.getTruckMessage
1718
import no.spk.fiskeoye.plugin.util.hideColumns
19+
import no.spk.fiskeoye.plugin.util.htmlToText
1820
import no.spk.fiskeoye.plugin.util.makeLabelIcon
1921
import no.spk.fiskeoye.plugin.util.makeUrl
22+
import no.spk.fiskeoye.plugin.util.stringWidth
23+
import no.spk.fiskeoye.plugin.util.update
2024
import org.jsoup.nodes.Element
2125
import javax.swing.SwingUtilities
2226
import javax.swing.table.DefaultTableModel
@@ -43,6 +47,7 @@ internal class FileContentSearchListener(private val fileContentPanel: FileConte
4347
indicator.isIndeterminate = true
4448

4549
try {
50+
maxWidth = 0
4651
val searchParams = getFileContentSearchParameters()
4752
val (requestUrl, elements) = getFileContent(
4853
searchText,
@@ -91,6 +96,7 @@ internal class FileContentSearchListener(private val fileContentPanel: FileConte
9196
mainTable.clear()
9297
mainTable.model = model
9398
mainTable.hideColumns()
99+
mainTable.update(maxWidth)
94100
urlLabel.text = requestUrl
95101
ActivityTracker.getInstance().inc()
96102
}
@@ -133,7 +139,7 @@ internal class FileContentSearchListener(private val fileContentPanel: FileConte
133139
if (count >= truncSize) {
134140
setColumnIdentifiers(
135141
arrayOf(
136-
"<html>$headerText. ${getTruckMessage(truncSize)}</html>",
142+
getHtml("$headerText. ${getTruckMessage(truncSize)}"),
137143
"url",
138144
"text"
139145
)
@@ -175,7 +181,9 @@ internal class FileContentSearchListener(private val fileContentPanel: FileConte
175181
}
176182

177183
private fun DefaultTableModel.addTableRow(result: SearchResultEntry) {
178-
val html = "<html>${result.file}:${result.line}:${result.code}</html>"
184+
val html = getHtml("${result.file}:${result.line}:${result.code}")
185+
val htmlWidth = fileContentPanel.mainTable.stringWidth(htmlToText(html))
186+
maxWidth = checkWidth(maxWidth, htmlWidth)
179187

180188
addRow(
181189
arrayOf(

src/main/kotlin/no/spk/fiskeoye/plugin/listeners/button/FilenameSearchListener.kt

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,13 +9,17 @@ import no.spk.fiskeoye.plugin.util.addMessage
99
import no.spk.fiskeoye.plugin.util.clear
1010
import no.spk.fiskeoye.plugin.util.getDefaultModel
1111
import no.spk.fiskeoye.plugin.util.getHeaderText
12+
import no.spk.fiskeoye.plugin.util.getHtml
1213
import no.spk.fiskeoye.plugin.util.getInvalidString
1314
import no.spk.fiskeoye.plugin.util.getProject
1415
import no.spk.fiskeoye.plugin.util.getService
1516
import no.spk.fiskeoye.plugin.util.getTruckMessage
1617
import no.spk.fiskeoye.plugin.util.hideColumns
18+
import no.spk.fiskeoye.plugin.util.htmlToText
1719
import no.spk.fiskeoye.plugin.util.makeLabelIcon
1820
import no.spk.fiskeoye.plugin.util.makeUrl
21+
import no.spk.fiskeoye.plugin.util.stringWidth
22+
import no.spk.fiskeoye.plugin.util.update
1923
import org.jsoup.nodes.Element
2024
import javax.swing.SwingUtilities
2125
import javax.swing.table.DefaultTableModel
@@ -40,6 +44,7 @@ internal class FilenameSearchListener(private val filenamePanel: FilenamePanel)
4044
indicator.isIndeterminate = true
4145

4246
try {
47+
maxWidth = 0
4348
val searchParams = getFilenameSearchParameters()
4449
val (requestUrl, elements) = getFilename(
4550
searchText,
@@ -84,6 +89,7 @@ internal class FilenameSearchListener(private val filenamePanel: FilenamePanel)
8489
mainTable.clear()
8590
mainTable.model = model
8691
mainTable.hideColumns()
92+
mainTable.update(maxWidth)
8793
urlLabel.text = requestUrl
8894
ActivityTracker.getInstance().inc()
8995
}
@@ -120,7 +126,7 @@ internal class FilenameSearchListener(private val filenamePanel: FilenamePanel)
120126
if (count >= truncSize) {
121127
setColumnIdentifiers(
122128
arrayOf(
123-
"<html>$headerText. ${getTruckMessage(truncSize)}</html>",
129+
getHtml("$headerText. ${getTruckMessage(truncSize)}"),
124130
"url",
125131
"text"
126132
)
@@ -129,7 +135,9 @@ internal class FilenameSearchListener(private val filenamePanel: FilenamePanel)
129135
}
130136

131137
private fun DefaultTableModel.addTableRow(element: Element) {
132-
val html = "<html>$element</html>"
138+
val html = getHtml("$element")
139+
val htmlWidth = filenamePanel.mainTable.stringWidth(htmlToText(html))
140+
maxWidth = checkWidth(maxWidth, htmlWidth)
133141
val url = element.attr("href")
134142
val text = element.text()
135143

src/main/kotlin/no/spk/fiskeoye/plugin/listeners/button/FiskoyeSearchActionListener.kt

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,21 @@
11
package no.spk.fiskeoye.plugin.listeners.button
22

33
import com.intellij.openapi.diagnostic.Logger
4+
import com.intellij.ui.components.JBLabel
45
import com.intellij.ui.table.JBTable
6+
import no.spk.fiskeoye.plugin.settings.FiskeoyeState
57
import no.spk.fiskeoye.plugin.util.addMessage
68
import no.spk.fiskeoye.plugin.util.getGeneralErrorMessage
9+
import org.apache.commons.text.StringEscapeUtils.escapeHtml4
10+
import java.awt.Font
711
import javax.swing.SwingUtilities
812

913
internal abstract class FiskoyeSearchActionListener : FiskeoyeActionListener() {
1014

1115
private val logger: Logger = Logger.getInstance(FiskoyeSearchActionListener::class.java)
1216

17+
protected var maxWidth = 0
18+
1319
protected abstract fun performSearch(searchText: String)
1420

1521
protected fun isValidSearchText(text: String): Boolean = text.isNotEmpty() && text.length >= 3
@@ -23,4 +29,12 @@ internal abstract class FiskoyeSearchActionListener : FiskeoyeActionListener() {
2329
mainTable.addMessage(getGeneralErrorMessage())
2430
}
2531

32+
protected fun checkWidth(width: Int, htmlWidth: Int): Int {
33+
return if (width < htmlWidth) {
34+
htmlWidth
35+
} else {
36+
width
37+
}
38+
}
39+
2640
}

src/main/kotlin/no/spk/fiskeoye/plugin/ui/FileContentPanel.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package no.spk.fiskeoye.plugin.ui
33
import com.intellij.openapi.actionSystem.DefaultActionGroup
44
import com.intellij.openapi.ui.SimpleToolWindowPanel
55
import com.intellij.ui.components.JBLabel
6-
import com.intellij.ui.components.JBScrollPane
76
import com.intellij.ui.components.JBTextField
87
import com.intellij.ui.table.JBTable
98
import no.spk.fiskeoye.plugin.actions.window.CustomFiskeoyeAction
@@ -58,7 +57,7 @@ internal class FileContentPanel : FiskeoyePanel() {
5857
this.toolbar = buildToolbar("FileContent Sub Navigator Toolbar", subActionGroup, true).apply {
5958
this.targetComponent = this@FileContentPanel
6059
}.component
61-
this.add(JBScrollPane(mainTable))
60+
this.add(buildScrollPane(mainTable))
6261
}
6362
this.add(mainPanel)
6463
}

src/main/kotlin/no/spk/fiskeoye/plugin/ui/FilenamePanel.kt

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package no.spk.fiskeoye.plugin.ui
33
import com.intellij.openapi.actionSystem.DefaultActionGroup
44
import com.intellij.openapi.ui.SimpleToolWindowPanel
55
import com.intellij.ui.components.JBLabel
6-
import com.intellij.ui.components.JBScrollPane
76
import com.intellij.ui.components.JBTextField
87
import com.intellij.ui.table.JBTable
98
import no.spk.fiskeoye.plugin.actions.window.CustomFiskeoyeAction
@@ -55,7 +54,7 @@ internal class FilenamePanel : FiskeoyePanel() {
5554
this.toolbar = buildToolbar("FileName Sub Navigator Toolbar", subActionGroup, true).apply {
5655
this.targetComponent = this@FilenamePanel
5756
}.component
58-
this.add(JBScrollPane(mainTable))
57+
this.add(buildScrollPane(mainTable))
5958
}
6059
this.add(mainPanel)
6160
}

src/main/kotlin/no/spk/fiskeoye/plugin/ui/FiskeoyePanel.kt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ import com.intellij.openapi.ui.JBPopupMenu
1111
import com.intellij.openapi.ui.SimpleToolWindowPanel
1212
import com.intellij.ui.PopupMenuListenerAdapter
1313
import com.intellij.ui.components.JBLabel
14+
import com.intellij.ui.components.JBScrollPane
1415
import com.intellij.ui.components.JBTextField
1516
import com.intellij.ui.table.JBTable
1617
import no.spk.fiskeoye.plugin.actions.window.AddResultToClipboardAction
@@ -37,6 +38,8 @@ import java.awt.event.KeyListener
3738
import javax.swing.JButton
3839
import javax.swing.JToggleButton
3940
import javax.swing.ListSelectionModel
41+
import javax.swing.ScrollPaneConstants.HORIZONTAL_SCROLLBAR_AS_NEEDED
42+
import javax.swing.ScrollPaneConstants.VERTICAL_SCROLLBAR_AS_NEEDED
4043
import javax.swing.event.PopupMenuEvent
4144

4245
internal abstract class FiskeoyePanel : SimpleToolWindowPanel(true, true), DumbAware {
@@ -68,6 +71,7 @@ internal abstract class FiskeoyePanel : SimpleToolWindowPanel(true, true), DumbA
6871
intercellSpacing = Dimension()
6972
componentPopupMenu = buildPopupMenu(this)
7073
font = buildFont()
74+
autoscrolls = false
7175
setDefaultRenderer(LabelIcon::class.java, LabelIconRenderer())
7276
setSelectionMode(ListSelectionModel.SINGLE_INTERVAL_SELECTION)
7377
setShowGrid(false)
@@ -79,6 +83,13 @@ internal abstract class FiskeoyePanel : SimpleToolWindowPanel(true, true), DumbA
7983
}
8084
}
8185

86+
protected fun buildScrollPane(table: JBTable): JBScrollPane {
87+
return JBScrollPane(table).apply {
88+
verticalScrollBarPolicy = VERTICAL_SCROLLBAR_AS_NEEDED
89+
horizontalScrollBarPolicy = HORIZONTAL_SCROLLBAR_AS_NEEDED
90+
}
91+
}
92+
8293
protected fun buildFont(): Font {
8394
val state = FiskeoyeState().state
8495
return Font(state.fontName, state.fontStyle.index, state.fontSize)

src/main/kotlin/no/spk/fiskeoye/plugin/util/FiskeoyeUtil.kt

Lines changed: 46 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import com.intellij.openapi.wm.ToolWindow
1010
import com.intellij.openapi.wm.ToolWindowManager
1111
import com.intellij.openapi.wm.WindowManager
1212
import com.intellij.ui.table.JBTable
13+
import com.intellij.ui.util.preferredHeight
1314
import no.spk.fiskeoye.plugin.component.LabelIcon
1415
import no.spk.fiskeoye.plugin.enum.ScrollDirection
1516
import no.spk.fiskeoye.plugin.icons.FiskeoyeIcons.Bitbucket
@@ -20,19 +21,29 @@ import no.spk.fiskeoye.plugin.ui.FileContentPanel
2021
import no.spk.fiskeoye.plugin.ui.FilenamePanel
2122
import no.spk.fiskeoye.plugin.ui.FiskeoyePanel
2223
import java.awt.Desktop
24+
import java.awt.Dimension
2325
import java.awt.Window
2426
import java.awt.datatransfer.StringSelection
2527
import java.net.URI
2628
import java.net.URL
29+
import javax.swing.JEditorPane
30+
import javax.swing.JTable.AUTO_RESIZE_ALL_COLUMNS
31+
import javax.swing.JTable.AUTO_RESIZE_OFF
32+
import javax.swing.JTable.AUTO_RESIZE_SUBSEQUENT_COLUMNS
2733
import javax.swing.table.DefaultTableModel
34+
import javax.swing.text.html.HTMLEditorKit
2835

2936
internal fun scrollTo(table: JBTable, direction: ScrollDirection) {
3037
val rowIndex = when (direction) {
3138
ScrollDirection.END -> table.rowCount - 1
3239
ScrollDirection.TOP -> 0
3340
}
3441
if (table.rowCount == 0 || rowIndex > table.rowCount) return
42+
if (!table.autoscrolls) {
43+
table.autoscrolls = true
44+
}
3545
table.changeSelection(rowIndex, 0, false, false)
46+
table.autoscrolls = false
3647
}
3748

3849
internal fun copy(textToCopy: String) {
@@ -94,6 +105,7 @@ internal fun openUrlWithBrowser(uri: URI) {
94105

95106
internal fun JBTable.clear() {
96107
this.model = DefaultTableModel()
108+
this.preferredSize = Dimension(0, 0)
97109
}
98110

99111
internal fun JBTable.addMessage(message: String) {
@@ -111,8 +123,37 @@ internal fun JBTable.hideColumns() {
111123
}
112124
}
113125

126+
internal fun JBTable.stringWidth(text: String): Int {
127+
val fontMetrics = this.getFontMetrics(this.font)
128+
return fontMetrics.stringWidth(text)
129+
}
130+
131+
internal fun JBTable.update(width: Int) {
132+
val rowHeight = this.rowHeight
133+
val headerHeight = this.tableHeader.preferredSize.height
134+
val height = headerHeight + (rowCount * rowHeight)
135+
136+
val parentWidth = this.parent.width
137+
if (width < parentWidth) {
138+
this.autoResizeMode = AUTO_RESIZE_ALL_COLUMNS
139+
this.preferredHeight = height
140+
return
141+
}
142+
143+
this.autoResizeMode = AUTO_RESIZE_OFF
144+
this.preferredSize = Dimension(width, height)
145+
}
146+
114147
internal fun Boolean.toOnOff(): String = if (this) "on" else "off"
115148

149+
fun htmlToText(html: String): String {
150+
val editorPane = JEditorPane().apply {
151+
editorKit = HTMLEditorKit()
152+
text = html
153+
}
154+
return editorPane.document.getText(0, editorPane.document.length)
155+
}
156+
116157
internal fun getHeaderText(include: String, isExcluded: Boolean, exclude: String, isCaseSensitive: Boolean): String {
117158
if (include.trim().isEmpty()) return ""
118159
if (isExcluded && exclude.isEmpty() && isCaseSensitive) {
@@ -184,5 +225,9 @@ internal fun getInvalidString(): String {
184225
}
185226

186227
internal fun getHtmlError(value: String): String {
187-
return "<html><span style=\"color:red;\">$value<span><html>"
228+
return "<span style=\"color:red;\">$value<span>"
229+
}
230+
231+
internal fun getHtml(value: String): String {
232+
return "<html>$value</html>"
188233
}

0 commit comments

Comments
 (0)