Skip to content

Commit 8650167

Browse files
- decreased and fixed height for navigation panel rows - change background color of navigation panel dynamically - applied new background color for navigation panel - used ComboBox for environment selector - fixed flickering of environment selector
1 parent 845ebf9 commit 8650167

File tree

6 files changed

+198
-166
lines changed

6 files changed

+198
-166
lines changed

CHANGELOG.md

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
# Changelog
22
All notable changes to this project will be documented in this file.
33

4+
## [2.0.40] - 2023-03-21
5+
### Changed
6+
- Quick instrumentation java code (#395)
7+
- Decreased and fixed height for navigation panel rows (#392)
8+
- Change background color of navigation panel dynamically (#392)
9+
- Applied new background color for navigation panel (#392)
10+
- Used ComboBox for environment selector (#392)
11+
- Fixed flickering of environment selector (#392)
12+
413
## [2.0.39] - 2023-03-17
514
### Changed
615
- Added Pycharm support
@@ -52,4 +61,5 @@ All notable changes to this project will be documented in this file.
5261
[2.0.37]: https://github.com/digma-ai/digma-intellij-plugin/compare/v2.0.36...v2.0.37
5362
[2.0.38]: https://github.com/digma-ai/digma-intellij-plugin/compare/v2.0.37...v2.0.38
5463
[2.0.39]: https://github.com/digma-ai/digma-intellij-plugin/compare/v2.0.38...v2.0.39
55-
[Unreleased]: https://github.com/digma-ai/digma-intellij-plugin/compare/v2.0.39...HEAD
64+
[2.0.39]: https://github.com/digma-ai/digma-intellij-plugin/compare/v2.0.39...v2.0.40
65+
[Unreleased]: https://github.com/digma-ai/digma-intellij-plugin/compare/v2.0.40...HEAD

src/main/kotlin/org/digma/intellij/plugin/ui/common/EnvironmentsDropdownPanel.kt

Lines changed: 102 additions & 136 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ import com.intellij.openapi.application.ApplicationManager
55
import com.intellij.openapi.diagnostic.Logger
66
import com.intellij.openapi.project.Project
77
import com.intellij.openapi.rd.util.launchBackground
8-
import com.intellij.ui.Gray
8+
import com.intellij.openapi.ui.ComboBox
99
import com.intellij.ui.JBColor
10+
import com.intellij.ui.SimpleListCellRenderer
1011
import com.intellij.util.Alarm
1112
import com.intellij.util.AlarmFactory
1213
import com.intellij.util.messages.MessageBusConnection
@@ -20,15 +21,21 @@ import org.digma.intellij.plugin.log.Log
2021
import org.digma.intellij.plugin.model.rest.usage.UsageStatusResult
2122
import org.digma.intellij.plugin.ui.model.environment.EnvironmentsSupplier
2223
import org.digma.intellij.plugin.ui.panels.DigmaResettablePanel
23-
import java.awt.*
24+
import java.awt.Cursor
25+
import java.awt.Dimension
26+
import java.awt.event.ComponentAdapter
27+
import java.awt.event.ComponentEvent
2428
import java.awt.event.MouseAdapter
2529
import java.awt.event.MouseEvent
2630
import java.util.*
2731
import java.util.concurrent.atomic.AtomicBoolean
2832
import java.util.concurrent.locks.ReentrantLock
29-
import javax.swing.*
33+
import javax.swing.BoxLayout
34+
import javax.swing.Icon
35+
import javax.swing.JList
3036
import javax.swing.event.PopupMenuEvent
3137
import javax.swing.event.PopupMenuListener
38+
import javax.swing.plaf.basic.BasicComboPopup
3239

3340
class EnvironmentsDropdownPanel(
3441
project: Project,
@@ -39,17 +46,14 @@ class EnvironmentsDropdownPanel(
3946
private val logger: Logger = Logger.getInstance(EnvironmentsDropdownPanel::class.java)
4047

4148
private val usageStatusChangeConnection: MessageBusConnection = project.messageBus.connect()
42-
private val usageStatusResult: UsageStatusResult
49+
private var usageStatusResult: UsageStatusResult
4350
private val project: Project
4451
private val rebuildPanelLock = ReentrantLock()
4552
private var selectedItem: String
4653
private val localHostname: String
4754
private val changeEnvAlarm: Alarm
4855
private val popupMenuOpened: AtomicBoolean = AtomicBoolean(false)
49-
// Determine the background color of the dark theme editor (example value used)
50-
private val darkThemeEditorBackgroundColor = JBColor.namedColor("Editor.background", Gray._50)
51-
// Create a new color object using the background color of the dark theme editor
52-
private val menuItemBackgroundColor = JBColor(darkThemeEditorBackgroundColor, darkThemeEditorBackgroundColor)
56+
private val wasNotInitializedYet: AtomicBoolean = AtomicBoolean(true)
5357

5458
init {
5559
usageStatusChangeConnection.subscribe(
@@ -91,16 +95,23 @@ class EnvironmentsDropdownPanel(
9195
}
9296

9397
private fun rebuildInBackground(usageStatus: UsageStatusResult) {
94-
val lifetimeDefinition = LifetimeDefinition()
95-
lifetimeDefinition.lifetime.launchBackground {
96-
rebuildPanelLock.lock()
97-
Log.log(logger::debug, "Lock acquired for rebuild EnvironmentsDropdownPanel process.")
98-
try {
99-
rebuild(usageStatus)
100-
} finally {
101-
rebuildPanelLock.unlock()
102-
Log.log(logger::debug, "Lock released for rebuild EnvironmentsDropdownPanel process.")
103-
lifetimeDefinition.terminate()
98+
if (!popupMenuOpened.get()) {
99+
if (usageStatus.environmentStatuses.size != usageStatusResult.environmentStatuses.size
100+
|| usageStatusResult.codeObjectStatuses.isEmpty() || wasNotInitializedYet.get()) {
101+
usageStatusResult = usageStatus
102+
103+
val lifetimeDefinition = LifetimeDefinition()
104+
lifetimeDefinition.lifetime.launchBackground {
105+
rebuildPanelLock.lock()
106+
Log.log(logger::debug, "Lock acquired for rebuild EnvironmentsDropdownPanel process.")
107+
try {
108+
rebuild(usageStatus)
109+
} finally {
110+
rebuildPanelLock.unlock()
111+
Log.log(logger::debug, "Lock released for rebuild EnvironmentsDropdownPanel process.")
112+
lifetimeDefinition.terminate()
113+
}
114+
}
104115
}
105116
}
106117
}
@@ -180,74 +191,102 @@ class EnvironmentsDropdownPanel(
180191
environmentsInfo: MutableMap<String, MutableMap<String, Any>>,
181192
hasUsageFunction: (String) -> Boolean
182193
) {
183-
val dropdownLabel = object : JLabel() {
184-
override fun getPreferredSize(): Dimension {
185-
val size = super.getPreferredSize()
186-
size.width += 20 // Add some extra space to fit the "Select an item" text
187-
return size
188-
}
189-
}
190-
dropdownLabel.icon = getDropDownIcon()
191-
dropdownLabel.text = selectedItem
192-
dropdownLabel.horizontalTextPosition = SwingConstants.LEFT
193-
dropdownLabel.verticalTextPosition = SwingConstants.CENTER
194-
val popupMenu = JPopupMenu()
195-
// Add header to the popupMenu
196-
val header = createHeader("Environment", "Data")
197-
popupMenu.add(header)
194+
val items = mutableListOf<String>()
195+
val icons = mutableListOf<Icon>()
196+
val environmentsInfo = environmentsInfo
198197

199198
for (envInfo in environmentsInfo) {
200199
val buttonData = envInfo.value
201200
val currEnv = envInfo.key
202201
val linkText = buttonData.getValue("linkText").toString()
203-
// val isSelectedEnv = buttonData.getValue("isSelectedEnv") as Boolean
204-
205-
// val icon: Icon = if (isSelectedEnv) Laf.Icons.Environment.ENVIRONMENT_HAS_USAGE else Laf.Icons.Environment.ENVIRONMENT_HAS_NO_USAGE
206202
val icon: Icon = if (hasUsageFunction(currEnv)) Laf.Icons.Environment.ENVIRONMENT_HAS_USAGE else Laf.Icons.Environment.ENVIRONMENT_HAS_NO_USAGE
203+
items.add(linkText)
204+
icons.add(icon)
205+
}
207206

208-
val menuItem = createMenuItem(linkText, icon)
209-
210-
menuItem.addActionListener { event ->
211-
selectedItem = linkText // Update the selected item
212-
dropdownLabel.text = linkText
213-
214-
val currentSelected: String = getSelected()
215-
216-
if (currentSelected === event.source) {
217-
return@addActionListener
218-
}
219-
220-
changeEnvAlarm.cancelAllRequests()
221-
changeEnvAlarm.addRequest({
222-
environmentsSupplier.setCurrent(currEnv)
223-
}, 100)
207+
if (items.size > 0) {
208+
// this flag fixes initial load issue
209+
wasNotInitializedYet.set(false)
210+
}
211+
val comboBox = ComboBox(items.toTypedArray())
212+
comboBox.renderer = object : SimpleListCellRenderer<String>() {
213+
override fun customize(list: JList<out String>, value: String, index: Int, selected: Boolean, hasFocus: Boolean) {
214+
text = value
215+
icon = icons.getOrElse(index) { null }
216+
foreground = if (selected) JBColor.WHITE else JBColor.BLACK
217+
background = if (selected) JBColor.BLUE else JBColor.WHITE
224218
}
225-
popupMenu.add(menuItem)
226219
}
227-
popupMenu.addPopupMenuListener(object : PopupMenuListener {
220+
221+
comboBox.addPopupMenuListener(object : PopupMenuListener {
228222
override fun popupMenuWillBecomeVisible(e: PopupMenuEvent?) {
229-
dropdownLabel.icon = Laf.Icons.General.ARROW_UP
230223
popupMenuOpened.set(true)
224+
// Set the width of the ComboBox to the width of the widest item when the popup menu is opened
225+
val popup = comboBox.getUI().getAccessibleChild(comboBox, 0)
226+
val popupList = (popup as? BasicComboPopup)?.list
227+
if (popupList != null) {
228+
val popupWidth = items.maxOfOrNull { comboBox.getFontMetrics(comboBox.font).stringWidth(it) } ?: 0
229+
comboBox.preferredSize = Dimension(popupWidth + 40, comboBox.preferredSize.height)
230+
}
231231
}
232+
232233
override fun popupMenuWillBecomeInvisible(e: PopupMenuEvent?) {
233-
dropdownLabel.icon = Laf.Icons.General.ARROW_DOWN
234+
// Reset the width of the ComboBox to the fixed width when the popup menu is closed
235+
comboBox.preferredSize = Dimension(30, comboBox.preferredSize.height)
234236
popupMenuOpened.set(false)
235237
}
238+
236239
override fun popupMenuCanceled(e: PopupMenuEvent?) {
237-
// Do nothing
240+
// Reset the width of the ComboBox to the fixed width when the popup menu is canceled
241+
comboBox.preferredSize = Dimension(30, comboBox.preferredSize.height)
238242
}
239243
})
240-
dropdownLabel.addMouseListener(object : MouseAdapter() {
241-
override fun mousePressed(e: MouseEvent) {
242-
popupMenu.show(dropdownLabel, 0, dropdownLabel.height)
244+
245+
comboBox.addActionListener { event ->
246+
selectedItem = comboBox.selectedItem?.toString() ?: "" // Update the selected item
247+
248+
val currentSelected: String = getSelected()
249+
250+
if (currentSelected === event.source) {
251+
return@addActionListener
252+
}
253+
254+
changeEnvAlarm.cancelAllRequests()
255+
changeEnvAlarm.addRequest({
256+
environmentsSupplier.setCurrent(adjustBackEnvNameIfNeeded(selectedItem))
257+
}, 100)
258+
}
259+
260+
// Remove the border around the ComboBox
261+
comboBox.background = Laf.Colors.EDITOR_BACKGROUND
262+
comboBox.isOpaque = false
263+
// Set a fixed width for the closed ComboBox
264+
comboBox.preferredSize = Dimension(30, comboBox.preferredSize.height)
265+
comboBox.selectedItem = getSelected()
266+
267+
this.add(comboBox)
268+
269+
// Add ComponentListener to detect resizing of parent component
270+
addComponentListener(object : ComponentAdapter() {
271+
override fun componentResized(e: ComponentEvent) {
272+
comboBox.hidePopup()
243273
}
244274
})
245275

246-
this.add(dropdownLabel)
276+
// Add MouseListener to detect click outside of ComboBox
277+
addMouseListener(object : MouseAdapter() {
278+
override fun mouseClicked(e: MouseEvent) {
279+
if (!comboBox.bounds.contains(e.point)) {
280+
comboBox.hidePopup()
281+
}
282+
}
283+
})
247284
}
248285

249-
private fun getDropDownIcon(): Icon {
250-
return if (popupMenuOpened.get()) Laf.Icons.General.ARROW_UP else Laf.Icons.General.ARROW_DOWN
286+
private fun adjustBackEnvNameIfNeeded(environment: String): String {
287+
return if (environment.equals(LOCAL_ENV, ignoreCase = true)) {
288+
(localHostname + SUFFIX_OF_LOCAL).uppercase(Locale.getDefault())
289+
} else environment
251290
}
252291

253292
private fun removeExistingComponentsIfPresent() {
@@ -283,77 +322,4 @@ class EnvironmentsDropdownPanel(
283322
}
284323
return txtValue
285324
}
286-
287-
private fun createMenuItem(text: String, icon: Icon): JMenuItem {
288-
val menuItem = JMenuItem()
289-
menuItem.layout = BorderLayout()
290-
291-
// Create a panel for the text and icon labels with a flexible horizontal gap
292-
val panel = JPanel()
293-
panel.layout = BoxLayout(panel, BoxLayout.LINE_AXIS)
294-
295-
val textLabel = JLabel(text)
296-
textLabel.horizontalAlignment = SwingConstants.LEFT
297-
textLabel.font = Font("Helvetica", Font.PLAIN, 12)
298-
textLabel.border = JBUI.Borders.empty(0, 5)
299-
300-
val iconLabel = JLabel(icon)
301-
iconLabel.horizontalAlignment = SwingConstants.RIGHT
302-
iconLabel.border = JBUI.Borders.empty(0, 5)
303-
304-
panel.add(textLabel)
305-
panel.add(Box.createHorizontalGlue())
306-
panel.add(iconLabel)
307-
308-
menuItem.add(panel, BorderLayout.CENTER)
309-
310-
// Set the background color of the menu item to the dark theme editor background color
311-
menuItem.background = menuItemBackgroundColor
312-
panel.background = menuItemBackgroundColor
313-
314-
// Add a mouse listener to highlight the menu item on mouse over
315-
menuItem.addMouseListener(object : MouseAdapter() {
316-
override fun mouseEntered(e: MouseEvent) {
317-
menuItem.cursor = Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)
318-
menuItem.background = Color.DARK_GRAY
319-
panel.background = Color.DARK_GRAY
320-
}
321-
322-
override fun mouseExited(e: MouseEvent) {
323-
menuItem.background = menuItemBackgroundColor
324-
panel.background = menuItemBackgroundColor
325-
}
326-
})
327-
// Remove the border around the focused menu item
328-
menuItem.border = BorderFactory.createEmptyBorder()
329-
330-
return menuItem
331-
}
332-
333-
private fun createHeader(leftText: String, rightText: String): JComponent {
334-
val headerPanel = JPanel()
335-
headerPanel.layout = BoxLayout(headerPanel, BoxLayout.LINE_AXIS)
336-
337-
val leftLabel = JLabel(leftText)
338-
leftLabel.font = Font("SF Pro Text", Font.TRUETYPE_FONT, 10)
339-
leftLabel.horizontalAlignment = SwingConstants.LEFT
340-
leftLabel.border = JBUI.Borders.empty(0, 5)
341-
leftLabel.foreground = Laf.Colors.DROP_DOWN_HEADER_TEXT_COLOR
342-
343-
val minGapSize = maxOf(10, SwingUtilities.computeStringWidth(leftLabel.getFontMetrics(leftLabel.font), leftText))
344-
345-
headerPanel.add(leftLabel)
346-
347-
headerPanel.add(Box.createHorizontalStrut(minGapSize)) // Add flexible horizontal gap
348-
349-
val rightLabel = JLabel(rightText)
350-
rightLabel.font = Font("SF Pro Text", Font.TRUETYPE_FONT, 10)
351-
rightLabel.horizontalAlignment = SwingConstants.RIGHT
352-
rightLabel.border = JBUI.Borders.empty(0, 5)
353-
rightLabel.foreground = Laf.Colors.DROP_DOWN_HEADER_TEXT_COLOR
354-
355-
headerPanel.add(rightLabel)
356-
headerPanel.background = menuItemBackgroundColor
357-
return headerPanel
358-
}
359325
}

src/main/kotlin/org/digma/intellij/plugin/ui/common/Laf.kt

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package org.digma.intellij.plugin.ui.common
22

33
import com.intellij.icons.AllIcons
4+
import com.intellij.openapi.editor.colors.GlobalEditorScheme
45
import com.intellij.ui.JBColor
56
import com.intellij.util.ui.JBUI
67
import org.digma.intellij.plugin.icons.IconsUtil
@@ -50,7 +51,7 @@ object Laf {
5051
companion object {
5152
@JvmStatic val DEFAULT_LABEL_FOREGROUND: Color = JBColor.foreground()
5253
@JvmStatic val PLUGIN_BACKGROUND: JBColor = JBColor.namedColor("Plugins.background", JBColor.PanelBackground)
53-
@JvmStatic val NAVIGATION_TOP_BACKGROUND_DARK: Color = Color(0x1E1E1E)
54+
@JvmStatic val EDITOR_BACKGROUND: JBColor = JBColor.namedColor("Editor.background", GlobalEditorScheme.getDefaultBackground())
5455
@JvmStatic val DROP_DOWN_HEADER_TEXT_COLOR: Color = Color(0x7C7C94)
5556
@JvmStatic val LIST_ITEM_BACKGROUND: JBColor = JBColor(Color(0, 0, 50, 15), Color(200, 200, 255, 20))
5657
@JvmStatic val TRANSPARENT: Color = Color(0, 0, 0, 0)
@@ -66,12 +67,12 @@ object Laf {
6667
class Icons{
6768
class General{
6869
companion object {
69-
@JvmStatic val HOME: Icon = SvgIcon.withColor("/icons/home.svg", Colors.NAVIGATION_TOP_BACKGROUND_DARK)
70-
@JvmStatic val ARROW_UP: Icon = SvgIcon.withColor("/icons/arrow-up.svg", Colors.NAVIGATION_TOP_BACKGROUND_DARK)
71-
@JvmStatic val ARROW_DOWN: Icon = SvgIcon.withColor("/icons/arrow-down.svg", Colors.NAVIGATION_TOP_BACKGROUND_DARK)
72-
@JvmStatic val DIGMA_LOGO: Icon = SvgIcon.withColor("/icons/digma-logo.svg", Colors.NAVIGATION_TOP_BACKGROUND_DARK)
73-
@JvmStatic val RELATED_INSIGHTS: Icon = SvgIcon.withColor("/icons/related-insights.svg", Colors.NAVIGATION_TOP_BACKGROUND_DARK)
74-
@JvmStatic val POINTER: Icon = SvgIcon.withColor("/icons/pointer.svg", Colors.NAVIGATION_TOP_BACKGROUND_DARK)
70+
@JvmStatic val HOME: Icon = SvgIcon.asIs("/icons/home.svg")
71+
@JvmStatic val ARROW_UP: Icon = SvgIcon.asIs("/icons/arrow-up.svg")
72+
@JvmStatic val ARROW_DOWN: Icon = SvgIcon.asIs("/icons/arrow-down.svg")
73+
@JvmStatic val DIGMA_LOGO: Icon = SvgIcon.asIs("/icons/digma-logo.svg")
74+
@JvmStatic val RELATED_INSIGHTS: Icon = SvgIcon.asIs("/icons/related-insights.svg")
75+
@JvmStatic val POINTER: Icon = SvgIcon.asIs("/icons/pointer.svg")
7576
}
7677
}
7778
class ErrorDetails{

0 commit comments

Comments
 (0)