diff --git a/plugins/github/resources/META-INF/plugin.xml b/plugins/github/resources/META-INF/plugin.xml index ae7dc5ba1313..b75bfa68dc04 100644 --- a/plugins/github/resources/META-INF/plugin.xml +++ b/plugins/github/resources/META-INF/plugin.xml @@ -79,6 +79,9 @@ + @@ -93,6 +96,9 @@ + diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRToolWindowTabsContentManager.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRToolWindowTabsContentManager.kt index bd393f94470f..2fe470127c1d 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRToolWindowTabsContentManager.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRToolWindowTabsContentManager.kt @@ -6,15 +6,19 @@ import com.intellij.openapi.project.Project import com.intellij.openapi.util.Disposer import com.intellij.openapi.util.Key import com.intellij.ui.content.* +import com.intellij.util.EventDispatcher import com.intellij.util.IJSwingUtilities import com.intellij.vcsUtil.VcsImplUtil import org.jetbrains.annotations.CalledInAwt import org.jetbrains.plugins.github.authentication.GithubAuthenticationManager import org.jetbrains.plugins.github.util.GitRemoteUrlCoordinates +import java.util.* import javax.swing.JPanel class GHPRToolWindowTabsContentManager(private val project: Project, private val contentManager: ContentManager) { + private val tabDisposalEventDispatcher = EventDispatcher.create(TabDisposalListener::class.java) + val currentTabs: Set get() = contentManager.contents.mapNotNull { it.remoteUrl }.toSet() @@ -38,8 +42,8 @@ class GHPRToolWindowTabsContentManager(private val project: Project, private val } @CalledInAwt - internal fun addTab(remoteUrl: GitRemoteUrlCoordinates, onDispose: Disposable) { - val content = createContent(remoteUrl, onDispose) + internal fun addTab(remoteUrl: GitRemoteUrlCoordinates) { + val content = createContent(remoteUrl) contentManager.addContent(content) updateTabNames() } @@ -56,10 +60,12 @@ class GHPRToolWindowTabsContentManager(private val project: Project, private val contentManager.setSelectedContent(content, true) } - private fun createContent(remoteUrl: GitRemoteUrlCoordinates, onDispose: Disposable): Content { + private fun createContent(remoteUrl: GitRemoteUrlCoordinates): Content { val disposable = Disposer.newDisposable() - Disposer.register(disposable, Disposable { updateTabNames() }) - Disposer.register(disposable, onDispose) + Disposer.register(disposable, Disposable { + updateTabNames() + tabDisposalEventDispatcher.multicaster.tabDisposed(remoteUrl) + }) val content = ContentFactory.SERVICE.getInstance().createContent(JPanel(null), remoteUrl.remote.name, false) content.isCloseable = true @@ -86,12 +92,20 @@ class GHPRToolWindowTabsContentManager(private val project: Project, private val } } + fun addTabDisposalEventListener(listener: TabDisposalListener) = tabDisposalEventDispatcher.addListener(listener) + + fun removeTabDisposalEventListener(listener: TabDisposalListener) = tabDisposalEventDispatcher.removeListener(listener) + private var Content.remoteUrl get() = getUserData(REMOTE_URL) set(value) { putUserData(REMOTE_URL, value) } + interface TabDisposalListener : EventListener { + fun tabDisposed(remoteUrl: GitRemoteUrlCoordinates) + } + companion object { private val INIT_DONE_KEY = Key("GHPR_CONTENT_INIT_DONE") private val REMOTE_URL = Key("GHPR_REMOTE_URL") diff --git a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRToolWindowTabsManager.kt b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRToolWindowTabsManager.kt index b7e44132277c..3d84ce652b43 100644 --- a/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRToolWindowTabsManager.kt +++ b/plugins/github/src/org/jetbrains/plugins/github/pullrequest/GHPRToolWindowTabsManager.kt @@ -2,13 +2,16 @@ package org.jetbrains.plugins.github.pullrequest import com.intellij.dvcs.repo.VcsRepositoryMappingListener -import com.intellij.openapi.Disposable +import com.intellij.ide.plugins.DynamicPluginListener +import com.intellij.ide.plugins.IdeaPluginDescriptor +import com.intellij.ide.plugins.PluginManager import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.application.runInEdt import com.intellij.openapi.components.Service import com.intellij.openapi.components.service import com.intellij.openapi.project.Project import com.intellij.openapi.project.ProjectManager +import com.intellij.openapi.project.ProjectManagerListener import com.intellij.openapi.wm.ToolWindowManager import git4idea.repo.GitRepository import git4idea.repo.GitRepositoryChangeListener @@ -27,10 +30,25 @@ internal class GHPRToolWindowTabsManager(private val project: Project) { private val gitHelper = GithubGitHelper.getInstance() private val settings = GithubPullRequestsProjectUISettings.getInstance(project) - internal var contentManager: GHPRToolWindowTabsContentManager? by observable(null) { _, _, _ -> - updateTabs() + private val tabDisposalListener = object : GHPRToolWindowTabsContentManager.TabDisposalListener { + + var muted = false + + override fun tabDisposed(remoteUrl: GitRemoteUrlCoordinates) { + if (!muted) { + if (gitHelper.getPossibleRemoteUrlCoordinates(project).contains(remoteUrl)) settings.addHiddenUrl(remoteUrl.url) + updateTabs() + } + } } + internal var contentManager: GHPRToolWindowTabsContentManager? + by observable(null) { _, oldManager, newManager -> + oldManager?.removeTabDisposalEventListener(tabDisposalListener) + newManager?.addTabDisposalEventListener(tabDisposalListener) + updateTabs() + } + @CalledInAwt fun isAvailable(): Boolean = getRemoteUrls().isNotEmpty() @@ -56,11 +74,7 @@ internal class GHPRToolWindowTabsManager(private val project: Project) { contentManager.removeTab(item) } for (item in delta.newItems) { - contentManager.addTab(item, Disposable { - //means that tab was closed by user - if (gitHelper.getPossibleRemoteUrlCoordinates(project).contains(item)) settings.addHiddenUrl(item.url) - ApplicationManager.getApplication().invokeLater({ updateTabs() }) { project.isDisposed } - }) + contentManager.addTab(item) } } afterUpdate?.invoke() @@ -91,6 +105,18 @@ internal class GHPRToolWindowTabsManager(private val project: Project) { } } + class BeforePluginUnloadListener(private val project: Project) : DynamicPluginListener { + override fun beforePluginUnload(pluginDescriptor: IdeaPluginDescriptor, isUpdate: Boolean) { + if (pluginDescriptor.pluginId == PluginManager.getInstance().getPluginOrPlatformByClassName(this::class.java.name)) { + muteTabDisposalListener(project) + } + } + } + + class BeforeProjectCloseListener : ProjectManagerListener { + override fun projectClosing(project: Project) = muteTabDisposalListener(project) + } + companion object { private inline fun runInEdt(project: Project, crossinline runnable: () -> Unit) { val application = ApplicationManager.getApplication() @@ -99,5 +125,9 @@ internal class GHPRToolWindowTabsManager(private val project: Project) { } private fun updateRemotes(project: Project) = project.service().updateTabs() + + private fun muteTabDisposalListener(project: Project) { + project.service().tabDisposalListener.muted = true + } } }