From 9fde169b6ad29762ec4d73b1a8cacf2b5a55ea9d Mon Sep 17 00:00:00 2001 From: "Nikita.Ashihmin" Date: Wed, 21 Aug 2024 00:19:39 +0400 Subject: [PATCH] PY-72994 Packages(refactor, feat): Update package actions GitOrigin-RevId: 12d6e92f838717817b6b3a69ae7b844ba1724be3 --- .../pluginCore/resources/META-INF/plugin.xml | 7 ++++ .../messages/PyBundle.properties | 10 ++++-- .../toolwindow/PyPackagingToolWindowPanel.kt | 7 ++++ .../PyPackagingToolWindowService.kt | 17 +++++---- .../actions/ChangeVersionPackageAction.kt | 16 ++++----- .../toolwindow/actions/DeletePackageAction.kt | 9 +++-- .../actions/InstallPackageAction.kt | 16 ++++----- .../actions/UpdatePackageToLatestAction.kt | 36 +++++-------------- .../toolwindow/ui/PyPackagesTable.kt | 14 ++------ .../toolwindow/ui/PyPackagesUiComponents.kt | 12 +++++++ .../ui/PyPaginationAwareRenderer.kt | 4 +-- 11 files changed, 78 insertions(+), 70 deletions(-) diff --git a/python/pluginCore/resources/META-INF/plugin.xml b/python/pluginCore/resources/META-INF/plugin.xml index 130c611bccc4..2a34bad1b3b4 100644 --- a/python/pluginCore/resources/META-INF/plugin.xml +++ b/python/pluginCore/resources/META-INF/plugin.xml @@ -914,6 +914,13 @@ The Python plug-in provides smart editing for Python scripts. The feature set of + + + + + + + diff --git a/python/pluginResources/messages/PyBundle.properties b/python/pluginResources/messages/PyBundle.properties index 70d01e5aae81..5abcd1edf9b1 100644 --- a/python/pluginResources/messages/PyBundle.properties +++ b/python/pluginResources/messages/PyBundle.properties @@ -1357,9 +1357,8 @@ python.toolwindow.packages.documentation.link=Documentation python.toolwindow.packages.no.interpreter.text=Select an interpreter to see the installed packages python.toolwindow.packages.latest.version.label=latest python.toolwindow.packages.delete.package=Uninstall -python.toolwindow.packages.update.package=Change Version python.toolwindow.packages.update.package.version=Update {0} -> {1} -python.toolwindow.packages.install.link=Install +action.python.packages.install.text=Install python.toolwindow.packages.search.text.placeholder=Search for more packages python.toolwindow.packages.description.panel.placeholder=Select a package to view documentation python.toolwindow.packages.no.description.placeholder=

Package author did not provide a description.

@@ -1525,4 +1524,9 @@ param.info.show.more.n.overloads=Show {0} more {1, choice, 0#overloads|1#overloa # Advertising advertiser.package.supported.by.pro={0} is supported by PyCharm Professional -advertiser.code.cells.supported.by.pro=Code cells are supported by PyCharm Professional \ No newline at end of file +advertiser.code.cells.supported.by.pro=Code cells are supported by PyCharm Professional + +action.PyInstallPackage.text=Install +action.PyDeletePackage.text=Uninstall +action.PyUpdateToLatestPackage.text=Update to Latest +action.PyChangeVersionPackage.text=Change Version \ No newline at end of file diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowPanel.kt b/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowPanel.kt index fd18a33e323e..a57149861c9c 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowPanel.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowPanel.kt @@ -6,6 +6,7 @@ import com.intellij.ide.BrowserUtil import com.intellij.openapi.Disposable import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.actionSystem.ActionPlaces +import com.intellij.openapi.actionSystem.DataSink import com.intellij.openapi.actionSystem.DefaultActionGroup import com.intellij.openapi.actionSystem.impl.ActionButton import com.intellij.openapi.application.ModalityState @@ -242,6 +243,12 @@ class PyPackagingToolWindowPanel(private val project: Project, toolWindow: ToolW trackOrientation(service) } + + override fun uiDataSnapshot(sink: DataSink) { + sink[PyPackagesUiComponents.SELECTED_PACKAGE_DATA_CONTEXT] = selectedPackage + super.uiDataSnapshot(sink) + } + private fun initOrientation(service: PyPackagingToolWindowService, horizontal: Boolean) { val second = if (splitter?.secondComponent == rightPanel) rightPanel else noPackagePanel val proportionKey = if (horizontal) HORIZONTAL_SPLITTER_KEY else VERTICAL_SPLITTER_KEY diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt b/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt index 1ca45e6e346e..54f133a5a33e 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/PyPackagingToolWindowService.kt @@ -51,8 +51,8 @@ import org.jetbrains.annotations.Nls @Service(Service.Level.PROJECT) class PyPackagingToolWindowService(val project: Project, val serviceScope: CoroutineScope) : Disposable { - - private var toolWindowPanel: PyPackagingToolWindowPanel? = null + var toolWindowPanel: PyPackagingToolWindowPanel? = null + private set lateinit var manager: PythonPackageManager private var installedPackages: Map = emptyMap() internal var currentSdk: Sdk? = null @@ -231,10 +231,12 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou } } - private fun sortPackagesForRepo(packageNames: List, - query: String, - repository: PyPackageRepository, - skipItems: Int = 0): PyPackagesViewData { + private fun sortPackagesForRepo( + packageNames: List, + query: String, + repository: PyPackageRepository, + skipItems: Int = 0, + ): PyPackagesViewData { val comparator = createNameComparator(query, repository.repositoryUrl ?: "") @@ -384,6 +386,9 @@ class PyPackagingToolWindowService(val project: Project, val serviceScope: Corou companion object { private const val PACKAGES_LIMIT = 50 + + fun getInstance(project: Project) = project.service() + private fun createNameComparator(query: String, url: String): Comparator { val nameComparator = Comparator { name1, name2 -> val queryLowerCase = query.lowercase() diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/actions/ChangeVersionPackageAction.kt b/python/src/com/jetbrains/python/packaging/toolwindow/actions/ChangeVersionPackageAction.kt index add9d01a9546..b0feb58b0466 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/actions/ChangeVersionPackageAction.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/actions/ChangeVersionPackageAction.kt @@ -4,39 +4,39 @@ package com.jetbrains.python.packaging.toolwindow.actions import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.application.EDT -import com.intellij.openapi.components.service import com.intellij.openapi.project.DumbAwareAction import com.intellij.ui.awt.RelativePoint -import com.jetbrains.python.PyBundle import com.jetbrains.python.packaging.toolwindow.PyPackagingToolWindowService import com.jetbrains.python.packaging.toolwindow.model.InstalledPackage -import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesTable import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesUiComponents +import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesUiComponents.selectedPackage import com.jetbrains.python.packaging.utils.PyPackageCoroutine import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch import kotlinx.coroutines.withContext import java.awt.event.MouseEvent -internal class ChangeVersionPackageAction(val table: PyPackagesTable<*>) : DumbAwareAction(PyBundle.message("python.toolwindow.packages.update.package")) { +internal class ChangeVersionPackageAction : DumbAwareAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return - val pkg = table.selectedItem() as? InstalledPackage ?: return + val pkg = e.selectedPackage as? InstalledPackage ?: return + val service = PyPackagingToolWindowService.getInstance(project) + val controller = service.toolWindowPanel ?: return PyPackageCoroutine.getIoScope(project).launch { - val service = project.service() val details = service.detailsForPackage(pkg) withContext(Dispatchers.EDT) { - PyPackagesUiComponents.createAvailableVersionsPopup(pkg, details, project, table.controller).show( + PyPackagesUiComponents.createAvailableVersionsPopup(pkg, details, project, controller).show( RelativePoint(e.inputEvent as MouseEvent)) } } } override fun update(e: AnActionEvent) { - val pkg = table.selectedItem() as? InstalledPackage + val pkg = e.selectedPackage as? InstalledPackage e.presentation.isEnabledAndVisible = pkg != null } override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT + } \ No newline at end of file diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/actions/DeletePackageAction.kt b/python/src/com/jetbrains/python/packaging/toolwindow/actions/DeletePackageAction.kt index 6d30ce0432d2..1e373db18e08 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/actions/DeletePackageAction.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/actions/DeletePackageAction.kt @@ -5,17 +5,16 @@ import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent import com.intellij.openapi.components.service import com.intellij.openapi.project.DumbAwareAction -import com.jetbrains.python.PyBundle import com.jetbrains.python.packaging.toolwindow.PyPackagingToolWindowService import com.jetbrains.python.packaging.toolwindow.model.InstalledPackage -import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesTable +import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesUiComponents.selectedPackage import com.jetbrains.python.packaging.utils.PyPackageCoroutine import kotlinx.coroutines.Dispatchers -internal class DeletePackageAction(val table: PyPackagesTable<*>) : DumbAwareAction(PyBundle.message("python.toolwindow.packages.delete.package")) { +internal class DeletePackageAction : DumbAwareAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return - val pkg = table.selectedItem() as? InstalledPackage ?: return + val pkg = e.selectedPackage as? InstalledPackage ?: return val service = project.service() @@ -25,7 +24,7 @@ internal class DeletePackageAction(val table: PyPackagesTable<*>) : DumbAwareAct } override fun update(e: AnActionEvent) { - e.presentation.isEnabledAndVisible = table.selectedItem() is InstalledPackage + e.presentation.isEnabledAndVisible = e.selectedPackage is InstalledPackage } override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/actions/InstallPackageAction.kt b/python/src/com/jetbrains/python/packaging/toolwindow/actions/InstallPackageAction.kt index 29a299fbe898..f53e7eafdfff 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/actions/InstallPackageAction.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/actions/InstallPackageAction.kt @@ -3,36 +3,36 @@ package com.jetbrains.python.packaging.toolwindow.actions import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.components.service import com.intellij.openapi.project.DumbAwareAction import com.intellij.ui.awt.RelativePoint -import com.jetbrains.python.PyBundle import com.jetbrains.python.packaging.toolwindow.PyPackagingToolWindowService import com.jetbrains.python.packaging.toolwindow.model.InstallablePackage -import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesTable import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesUiComponents +import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesUiComponents.selectedPackage import com.jetbrains.python.packaging.utils.PyPackageCoroutine import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.withContext import java.awt.event.MouseEvent -internal class InstallPackageAction(val table: PyPackagesTable<*>) : DumbAwareAction(PyBundle.message("python.toolwindow.packages.install.link")) { +internal class InstallPackageAction : DumbAwareAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return - val service = project.service() - val pkg = table.selectedItem() as? InstallablePackage ?: return + val pkg = e.selectedPackage as? InstallablePackage ?: return + + val service = PyPackagingToolWindowService.getInstance(project) + val controller = service.toolWindowPanel ?: return PyPackageCoroutine.launch(project, Dispatchers.IO) { val details = service.detailsForPackage(pkg) withContext(Dispatchers.Main) { - val popup = PyPackagesUiComponents.createAvailableVersionsPopup(pkg, details, project, table.controller) + val popup = PyPackagesUiComponents.createAvailableVersionsPopup(pkg, details, project, controller) popup.show(RelativePoint(e.inputEvent as MouseEvent)) } } } override fun update(e: AnActionEvent) { - e.presentation.isEnabledAndVisible = table.selectedItem() is InstallablePackage + e.presentation.isEnabledAndVisible = e.selectedPackage is InstallablePackage } override fun getActionUpdateThread(): ActionUpdateThread = ActionUpdateThread.BGT diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/actions/UpdatePackageToLatestAction.kt b/python/src/com/jetbrains/python/packaging/toolwindow/actions/UpdatePackageToLatestAction.kt index 9eee348b1223..5323fd0d637f 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/actions/UpdatePackageToLatestAction.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/actions/UpdatePackageToLatestAction.kt @@ -3,47 +3,29 @@ package com.jetbrains.python.packaging.toolwindow.actions import com.intellij.openapi.actionSystem.ActionUpdateThread import com.intellij.openapi.actionSystem.AnActionEvent -import com.intellij.openapi.application.EDT -import com.intellij.openapi.components.service import com.intellij.openapi.project.DumbAwareAction -import com.intellij.ui.awt.RelativePoint import com.jetbrains.python.PyBundle import com.jetbrains.python.packaging.toolwindow.PyPackagingToolWindowService -import com.jetbrains.python.packaging.toolwindow.model.InstallablePackage import com.jetbrains.python.packaging.toolwindow.model.InstalledPackage -import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesTable -import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesUiComponents +import com.jetbrains.python.packaging.toolwindow.ui.PyPackagesUiComponents.selectedPackage import com.jetbrains.python.packaging.utils.PyPackageCoroutine -import kotlinx.coroutines.Dispatchers import kotlinx.coroutines.launch -import kotlinx.coroutines.withContext -import java.awt.event.MouseEvent -internal class UpdatePackageToLatestAction(val table: PyPackagesTable<*>) : DumbAwareAction(PyBundle.message("python.toolwindow.packages.update.package")) { +internal class UpdatePackageToLatestAction : DumbAwareAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return - val pkg = table.selectedItem() + val pkg = e.selectedPackage as? InstalledPackage ?: return - val service = project.service() - if (pkg is InstalledPackage && pkg.canBeUpdated) { - PyPackageCoroutine.getIoScope(project).launch { - val specification = pkg.repository.createPackageSpecification(pkg.name, pkg.nextVersion!!.presentableText) - service.updatePackage(specification) - } - } - else if (pkg is InstallablePackage) { - PyPackageCoroutine.getIoScope(project).launch { - val details = service.detailsForPackage(pkg) - withContext(Dispatchers.EDT) { - PyPackagesUiComponents.createAvailableVersionsPopup(pkg, details, project, table.controller).show( - RelativePoint(e.inputEvent as MouseEvent)) - } - } + val service = PyPackagingToolWindowService.getInstance(project) + + PyPackageCoroutine.getIoScope(project).launch { + val specification = pkg.repository.createPackageSpecification(pkg.name, pkg.nextVersion!!.presentableText) + service.updatePackage(specification) } } override fun update(e: AnActionEvent) { - val pkg = table.selectedItem() as? InstalledPackage + val pkg = e.selectedPackage as? InstalledPackage val currentVersion = pkg?.currentVersion?.presentableText val nextVersion = pkg?.nextVersion?.presentableText diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPackagesTable.kt b/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPackagesTable.kt index e18ca5d01e70..f5e0bc7b9d86 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPackagesTable.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPackagesTable.kt @@ -1,7 +1,8 @@ // Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license. package com.jetbrains.python.packaging.toolwindow.ui -import com.intellij.openapi.actionSystem.DefaultActionGroup +import com.intellij.openapi.actionSystem.ActionGroup +import com.intellij.openapi.actionSystem.ActionManager import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.ui.DoubleClickListener @@ -15,10 +16,6 @@ import com.intellij.util.ui.NamedColorUtil import com.jetbrains.python.packaging.toolwindow.PyPackagingTablesView import com.jetbrains.python.packaging.toolwindow.PyPackagingToolWindowPanel import com.jetbrains.python.packaging.toolwindow.PyPackagingToolWindowService -import com.jetbrains.python.packaging.toolwindow.actions.ChangeVersionPackageAction -import com.jetbrains.python.packaging.toolwindow.actions.DeletePackageAction -import com.jetbrains.python.packaging.toolwindow.actions.InstallPackageAction -import com.jetbrains.python.packaging.toolwindow.actions.UpdatePackageToLatestAction import com.jetbrains.python.packaging.toolwindow.model.DisplayablePackage import com.jetbrains.python.packaging.toolwindow.model.ExpandResultNode import com.jetbrains.python.packaging.toolwindow.model.InstallablePackage @@ -127,12 +124,7 @@ internal class PyPackagesTable( } }.installOn(this) - val packageActionGroup = DefaultActionGroup( - DeletePackageAction(this), - InstallPackageAction(this), - UpdatePackageToLatestAction(this), - ChangeVersionPackageAction(this), - ) + val packageActionGroup = ActionManager.getInstance().getAction("PyPackageToolwindowContext") as ActionGroup PopupHandler.installPopupMenu(this, packageActionGroup, "PackagePopup") } diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPackagesUiComponents.kt b/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPackagesUiComponents.kt index c479813ba9fb..8ff536db6886 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPackagesUiComponents.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPackagesUiComponents.kt @@ -2,6 +2,9 @@ package com.jetbrains.python.packaging.toolwindow.ui import com.intellij.icons.AllIcons +import com.intellij.openapi.actionSystem.AnActionEvent +import com.intellij.openapi.actionSystem.DataContext +import com.intellij.openapi.actionSystem.DataKey import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.openapi.ui.popup.JBPopupFactory @@ -25,6 +28,15 @@ import java.awt.event.MouseEvent import javax.swing.* object PyPackagesUiComponents { + val SELECTED_PACKAGE_DATA_CONTEXT = DataKey.create("SELECTED_PACKAGE_DATA_CONTEXT") + + val DataContext.selectedPackage: DisplayablePackage? + get() = getData(SELECTED_PACKAGE_DATA_CONTEXT) + + val AnActionEvent.selectedPackage: DisplayablePackage? + get() = dataContext.selectedPackage + + fun createAvailableVersionsPopup(selectedPackage: DisplayablePackage, details: PythonPackageDetails, project: Project, controller: PyPackagingToolWindowPanel): ListPopup { return JBPopupFactory.getInstance().createListPopup(object : BaseListPopupStep(null, details.availableVersions) { override fun onChosen(selectedValue: String?, finalChoice: Boolean): PopupStep<*>? { diff --git a/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPaginationAwareRenderer.kt b/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPaginationAwareRenderer.kt index efb4bc4492e4..948441caeee5 100644 --- a/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPaginationAwareRenderer.kt +++ b/python/src/com/jetbrains/python/packaging/toolwindow/ui/PyPaginationAwareRenderer.kt @@ -21,7 +21,7 @@ import javax.swing.table.DefaultTableCellRenderer internal class PyPaginationAwareRenderer : DefaultTableCellRenderer() { private val nameLabel = JLabel().apply { border = JBUI.Borders.empty(0, 12) } private val versionLabel = JLabel().apply { border = JBUI.Borders.emptyRight(12) } - private val linkLabel = JLabel(PyBundle.message("python.toolwindow.packages.install.link")).apply { + private val linkLabel = JLabel(PyBundle.message("action.python.packages.install.text")).apply { border = JBUI.Borders.emptyRight(12) foreground = JBUI.CurrentTheme.Link.Foreground.ENABLED } @@ -67,7 +67,7 @@ internal class PyPaginationAwareRenderer : DefaultTableCellRenderer() { versionPanel.removeAll() if (value is InstallablePackage) { - linkLabel.text = PyBundle.message("python.toolwindow.packages.install.link") + linkLabel.text = PyBundle.message("action.python.packages.install.text") linkLabel.updateUnderline(table, row) if (rowSelected || TableHoverListener.getHoveredRow(table) == row) { versionPanel.add(linkLabel)