33
44package software.aws.toolkits.jetbrains.services.codewhisperer.codescan
55
6- import com.intellij.analysis.problemsView.toolWindow.ProblemsView
76import com.intellij.codeHighlighting.HighlightDisplayLevel
87import com.intellij.codeInspection.util.InspectionMessage
98import com.intellij.icons.AllIcons
109import com.intellij.lang.Commenter
1110import com.intellij.lang.Language
1211import com.intellij.lang.LanguageCommenters
12+ import com.intellij.openapi.Disposable
1313import com.intellij.openapi.actionSystem.ActionManager
1414import com.intellij.openapi.actionSystem.AnActionEvent
1515import com.intellij.openapi.actionSystem.CommonDataKeys
@@ -36,8 +36,10 @@ import com.intellij.openapi.util.Disposer
3636import com.intellij.openapi.util.TextRange
3737import com.intellij.openapi.vfs.VirtualFile
3838import com.intellij.openapi.vfs.isFile
39+ import com.intellij.openapi.wm.ToolWindow
3940import com.intellij.psi.PsiDocumentManager
4041import com.intellij.refactoring.suggested.range
42+ import com.intellij.ui.content.Content
4143import com.intellij.ui.content.ContentManagerEvent
4244import com.intellij.ui.content.ContentManagerListener
4345import com.intellij.ui.treeStructure.Tree
@@ -60,6 +62,7 @@ import software.aws.toolkits.core.utils.error
6062import software.aws.toolkits.core.utils.getLogger
6163import software.aws.toolkits.core.utils.info
6264import software.aws.toolkits.core.utils.warn
65+ import software.aws.toolkits.jetbrains.ProblemsViewMutator
6366import software.aws.toolkits.jetbrains.core.coroutines.EDT
6467import software.aws.toolkits.jetbrains.core.coroutines.getCoroutineUiContext
6568import software.aws.toolkits.jetbrains.core.coroutines.projectCoroutineScope
@@ -107,26 +110,10 @@ import kotlin.coroutines.CoroutineContext
107110
108111private val LOG = getLogger<CodeWhispererCodeScanManager >()
109112
110- class CodeWhispererCodeScanManager (val project : Project ) {
111- private val defaultScope = projectCoroutineScope(project)
113+ class CodeWhispererCodeScanManager (val project : Project , private val defaultScope : CoroutineScope ) : Disposable {
112114 private val codeScanResultsPanel by lazy {
113115 CodeWhispererCodeScanResultsView (project, defaultScope)
114116 }
115- private val codeScanIssuesContent by lazy {
116- val contentManager = getProblemsWindow().contentManager
117- contentManager.factory.createContent(
118- codeScanResultsPanel,
119- message(" codewhisperer.codescan.scan_display" ),
120- false
121- ).also {
122- Disposer .register(contentManager, it)
123- contentManager.addContentManagerListener(object : ContentManagerListener {
124- override fun contentRemoved (event : ContentManagerEvent ) {
125- if (event.content == it) reset()
126- }
127- })
128- }
129- }
130117
131118 private var autoScanIssues = emptyList<CodeWhispererCodeScanIssue >()
132119 private var ondemandScanIssues = emptyList<CodeWhispererCodeScanIssue >()
@@ -507,12 +494,19 @@ class CodeWhispererCodeScanManager(val project: Project) {
507494 private fun refreshUi () {
508495 val codeScanTreeModel = CodeWhispererCodeScanTreeModel (codeScanTreeNodeRoot)
509496 val totalIssuesCount = codeScanTreeModel.getTotalIssuesCount()
510- if (totalIssuesCount > 0 ) {
511- codeScanIssuesContent.displayName =
512- message(" codewhisperer.codescan.scan_display_with_issues" , totalIssuesCount, INACTIVE_TEXT_COLOR )
497+ val displayName = if (totalIssuesCount > 0 ) {
498+ message(" codewhisperer.codescan.scan_display_with_issues" , totalIssuesCount, INACTIVE_TEXT_COLOR )
513499 } else {
514- codeScanIssuesContent.displayName = message(" codewhisperer.codescan.scan_display" )
500+ message(" codewhisperer.codescan.scan_display" )
515501 }
502+
503+ withToolWindow { window ->
504+ window.contentManager.contents.filter { it.isCodeScanView() }
505+ .forEach {
506+ it.displayName = displayName
507+ }
508+ }
509+
516510 codeScanResultsPanel.refreshUIWithUpdatedModel(codeScanTreeModel)
517511 }
518512
@@ -650,26 +644,45 @@ class CodeWhispererCodeScanManager(val project: Project) {
650644 * This method adds code content to the problems view if not already added.
651645 */
652646 fun buildCodeScanUI () = runInEdt {
653- val problemsWindow = getProblemsWindow()
654- if (! problemsWindow.contentManager.contents.contains(codeScanIssuesContent)) {
655- problemsWindow.contentManager.addContent(codeScanIssuesContent)
656- codeScanIssuesContent.displayName = message(" codewhisperer.codescan.scan_display" )
647+ withToolWindow { problemsWindow ->
648+ val contentManager = problemsWindow.contentManager
649+ if (! contentManager.contents.any { it.isCodeScanView() }) {
650+ contentManager.addContent(
651+ contentManager.factory.createContent(
652+ codeScanResultsPanel,
653+ message(" codewhisperer.codescan.scan_display" ),
654+ false
655+ ).also {
656+ it.tabName = message(" codewhisperer.codescan.scan_display" )
657+ Disposer .register(contentManager, it)
658+ contentManager.addContentManagerListener(object : ContentManagerListener {
659+ override fun contentRemoved (event : ContentManagerEvent ) {
660+ if (event.content == it) reset()
661+ }
662+ })
663+ }
664+ )
665+ }
657666 }
658667 }
659668
660669 /* *
661670 * This method shows the code content panel in problems view
662671 */
663672 fun showCodeScanUI () = runInEdt {
664- val problemsWindow = getProblemsWindow()
665- problemsWindow.contentManager.setSelectedContent(codeScanIssuesContent)
666- problemsWindow.show()
673+ withToolWindow { problemsWindow ->
674+ problemsWindow.contentManager.contents.firstOrNull { it.isCodeScanView() }
675+ ?.let { problemsWindow.contentManager.setSelectedContent(it) }
676+ problemsWindow.show()
677+ }
667678 }
668679
669680 fun removeCodeScanUI () = runInEdt {
670- val problemsWindow = getProblemsWindow()
671- if (problemsWindow.contentManager.contents.contains(codeScanIssuesContent)) {
672- problemsWindow.contentManager.removeContent(codeScanIssuesContent, false )
681+ withToolWindow { problemsWindow ->
682+ problemsWindow.contentManager.contents.filter { it.isCodeScanView() }
683+ .forEach {
684+ problemsWindow.contentManager.removeContent(it, true )
685+ }
673686 }
674687 }
675688
@@ -735,8 +748,13 @@ class CodeWhispererCodeScanManager(val project: Project) {
735748 )
736749 }
737750
738- private fun getProblemsWindow () = ProblemsView .getToolWindow(project)
739- ? : error(message(" codewhisperer.codescan.problems_window_not_found" ))
751+ private fun withToolWindow (runnable : (ToolWindow ) -> Unit ) {
752+ ProblemsViewMutator .EP .forEachExtensionSafe { mutator ->
753+ mutator.mutateProblemsView(project, runnable)
754+ }
755+ }
756+
757+ private fun Content.isCodeScanView () = component == codeScanResultsPanel
740758
741759 private fun reset () = runInEdt {
742760 // clear the codeScanTreeNodeRoot
@@ -765,7 +783,7 @@ class CodeWhispererCodeScanManager(val project: Project) {
765783 editorFactory.addEditorFactoryListener(fileListener, project)
766784 editorFactory.eventMulticaster.addEditorMouseMotionListener(
767785 editorMouseListener,
768- codeScanIssuesContent
786+ this
769787 )
770788 }
771789 }
@@ -955,8 +973,12 @@ class CodeWhispererCodeScanManager(val project: Project) {
955973 val codeScanTreeModel = CodeWhispererCodeScanTreeModel (codeScanTreeNodeRoot)
956974 val totalIssuesCount = codeScanTreeModel.getTotalIssuesCount()
957975 if (totalIssuesCount > 0 ) {
958- codeScanIssuesContent.displayName =
959- message(" codewhisperer.codescan.scan_display_with_issues" , totalIssuesCount, INACTIVE_TEXT_COLOR )
976+ withToolWindow {
977+ it.contentManager.contents.filter { it.isCodeScanView() }
978+ .forEach {
979+ it.displayName = message(" codewhisperer.codescan.scan_display_with_issues" , totalIssuesCount, INACTIVE_TEXT_COLOR )
980+ }
981+ }
960982 }
961983 codeScanResultsPanel.refreshUIWithUpdatedModel(codeScanTreeModel)
962984 }
@@ -971,8 +993,13 @@ class CodeWhispererCodeScanManager(val project: Project) {
971993 val codeScanTreeModel = CodeWhispererCodeScanTreeModel (root)
972994 val totalIssuesCount = codeScanTreeModel.getTotalIssuesCount()
973995 if (totalIssuesCount > 0 ) {
974- codeScanIssuesContent.displayName =
975- message(" codewhisperer.codescan.scan_display_with_issues" , totalIssuesCount, INACTIVE_TEXT_COLOR )
996+ withToolWindow { window ->
997+ window.contentManager.contents.filter { it.isCodeScanView() }
998+ .forEach {
999+ it.displayName =
1000+ message(" codewhisperer.codescan.scan_display_with_issues" , totalIssuesCount, INACTIVE_TEXT_COLOR )
1001+ }
1002+ }
9761003 }
9771004 codeScanResultsPanel.updateAndDisplayScanResults(codeScanTreeModel, scannedFiles, scope)
9781005 }
@@ -1004,6 +1031,9 @@ class CodeWhispererCodeScanManager(val project: Project) {
10041031 return isInsideWorkTree(projectDir)
10051032 }
10061033
1034+ override fun dispose () {
1035+ }
1036+
10071037 companion object {
10081038 fun getInstance (project : Project ): CodeWhispererCodeScanManager = project.service()
10091039 }
0 commit comments