mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-01-05 01:50:56 +07:00
IJPL-175686 Add statistics for structure toolwindow usage
GitOrigin-RevId: ac2e065a46020ea18d0261ed2b6be793f1b2c2b5
This commit is contained in:
committed by
intellij-monorepo-bot
parent
a67f5da3aa
commit
e412c274f6
@@ -8,6 +8,7 @@ import com.intellij.ide.structureView.StructureView
|
||||
import com.intellij.ide.structureView.StructureViewBuilder
|
||||
import com.intellij.ide.structureView.StructureViewWrapper
|
||||
import com.intellij.ide.structureView.TextEditorBasedStructureViewModel
|
||||
import com.intellij.ide.structureView.StructureViewEventsCollector
|
||||
import com.intellij.ide.structureView.impl.StructureViewComposite
|
||||
import com.intellij.ide.structureView.impl.StructureViewComposite.StructureViewDescriptor
|
||||
import com.intellij.ide.structureView.impl.StructureViewState
|
||||
@@ -47,6 +48,7 @@ import com.intellij.ui.ExperimentalUI
|
||||
import com.intellij.ui.components.JBPanelWithEmptyText
|
||||
import com.intellij.ui.content.ContentFactory
|
||||
import com.intellij.ui.content.ContentManagerEvent
|
||||
import com.intellij.ui.content.ContentManagerEvent.ContentOperation
|
||||
import com.intellij.ui.content.ContentManagerListener
|
||||
import com.intellij.ui.switcher.QuickActionProvider
|
||||
import com.intellij.util.BitUtil
|
||||
@@ -72,7 +74,6 @@ import java.util.concurrent.atomic.AtomicReference
|
||||
import javax.swing.JComponent
|
||||
import javax.swing.JPanel
|
||||
import javax.swing.SwingUtilities
|
||||
import kotlin.jvm.Throws
|
||||
|
||||
@OptIn(FlowPreview::class)
|
||||
class StructureViewWrapperImpl(
|
||||
@@ -140,15 +141,20 @@ class StructureViewWrapperImpl(
|
||||
scheduleRebuild()
|
||||
}
|
||||
myToolWindow.contentManager.addContentManagerListener(object : ContentManagerListener {
|
||||
var currentIndex = -1 // to distinguish event "another tab selected" from "contents were removed and added"
|
||||
override fun selectionChanged(event: ContentManagerEvent) {
|
||||
if (myStructureView is StructureViewComposite) {
|
||||
val views = (myStructureView as StructureViewComposite).structureViews
|
||||
for (view in views) {
|
||||
views.forEachIndexed { i, view ->
|
||||
if (view.title == event.content.tabName) {
|
||||
coroutineScope.launch {
|
||||
updateHeaderActions(view.structureView)
|
||||
}
|
||||
break
|
||||
if (myToolWindow.contentManager.contentCount == 2 && i != currentIndex && event.operation == ContentOperation.add) {
|
||||
if (i != -1) StructureViewEventsCollector.logTabSelected(view)
|
||||
currentIndex = i
|
||||
}
|
||||
return@forEachIndexed
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -426,10 +432,16 @@ class StructureViewWrapperImpl(
|
||||
|
||||
myFileEditor = editor
|
||||
Disposer.register(this@StructureViewWrapperImpl, structureView)
|
||||
val previouslySelectedTab = StructureViewState.getInstance(project).selectedTab
|
||||
if (structureView is StructureViewComposite) {
|
||||
val views: Array<StructureViewDescriptor> = structureView.structureViews
|
||||
names = views.map { it.title }.toTypedArray()
|
||||
panels = views.map { createContentPanel(it.structureView.component) }
|
||||
panels = views.map {
|
||||
if (previouslySelectedTab == it.title) {
|
||||
StructureViewEventsCollector.logBuildStructure(it)
|
||||
}
|
||||
createContentPanel(it.structureView.component)
|
||||
}
|
||||
}
|
||||
else {
|
||||
createSinglePanel(structureView.component)
|
||||
|
||||
@@ -1036,6 +1036,7 @@
|
||||
|
||||
<projectService serviceInterface="com.intellij.ide.structureView.StructureViewFactory"
|
||||
serviceImplementation="com.intellij.ide.structureView.impl.StructureViewFactoryImpl"/>
|
||||
<statistics.counterUsagesCollector implementationClass="com.intellij.ide.structureView.StructureViewEventsCollector"/>
|
||||
<projectService serviceInterface="com.intellij.codeInspection.InspectionManager"
|
||||
serviceImplementation="com.intellij.codeInspection.ex.InspectionManagerEx"/>
|
||||
<documentationProvider implementation="com.intellij.codeInspection.actions.InspectionDescriptionDocumentationProvider"/>
|
||||
|
||||
@@ -21,5 +21,6 @@
|
||||
<orderEntry type="module" module-name="intellij.platform.util.ui" />
|
||||
<orderEntry type="library" name="fastutil-min" level="project" />
|
||||
<orderEntry type="module" module-name="intellij.platform.core.ui" />
|
||||
<orderEntry type="module" module-name="intellij.platform.statistics" />
|
||||
</component>
|
||||
</module>
|
||||
@@ -0,0 +1,80 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.structureView
|
||||
|
||||
import com.intellij.ide.structureView.impl.StructureViewComposite.StructureViewDescriptor
|
||||
import com.intellij.ide.structureView.logical.StructureViewTab
|
||||
import com.intellij.ide.structureView.logical.impl.LogicalStructureViewModel
|
||||
import com.intellij.ide.structureView.logical.impl.LogicalStructureViewTreeElement
|
||||
import com.intellij.internal.statistic.eventLog.EventLogGroup
|
||||
import com.intellij.internal.statistic.eventLog.events.EventFields
|
||||
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
object StructureViewEventsCollector: CounterUsagesCollector() {
|
||||
private val GROUP = EventLogGroup("structure.view", 1)
|
||||
override fun getGroup(): EventLogGroup = GROUP
|
||||
|
||||
private val TAB = EventFields.Enum<StructureViewTab>("tab")
|
||||
private val MODEL_CLASS = EventFields.Class("model.class")
|
||||
|
||||
|
||||
private val BUILD_STRUCTURE = GROUP.registerEvent(
|
||||
"toolwindow.shown",
|
||||
TAB, MODEL_CLASS,
|
||||
"Toolwindow is opened, first time or after changing a file"
|
||||
)
|
||||
private val TAB_SELECTED = GROUP.registerEvent(
|
||||
"tab.selected",
|
||||
TAB, MODEL_CLASS,
|
||||
"User selected another tab"
|
||||
)
|
||||
private val NAVIGATE = GROUP.registerEvent(
|
||||
"navigate",
|
||||
MODEL_CLASS,
|
||||
"Navigate to psiElement"
|
||||
)
|
||||
private val CUSTOM_CLICK_HANDLED = GROUP.registerEvent(
|
||||
"custom.click.handled",
|
||||
MODEL_CLASS,
|
||||
"Click event was handled by custom handler"
|
||||
)
|
||||
|
||||
fun logBuildStructure(viewDescriptor: StructureViewDescriptor) {
|
||||
val tab = viewDescriptor.title?.let { StructureViewTab.ofTitle(it) } ?: return
|
||||
BUILD_STRUCTURE.log(tab, getModelClass(viewDescriptor))
|
||||
}
|
||||
|
||||
fun logTabSelected(viewDescriptor: StructureViewDescriptor) {
|
||||
val tab = viewDescriptor.title?.let { StructureViewTab.ofTitle(it) } ?: return
|
||||
TAB_SELECTED.log(tab, getModelClass(viewDescriptor))
|
||||
}
|
||||
|
||||
fun logNavigate(modelClass: Class<*>) {
|
||||
NAVIGATE.log(modelClass)
|
||||
}
|
||||
|
||||
fun logCustomClickHandled(modelClass: Class<*>) {
|
||||
CUSTOM_CLICK_HANDLED.log(modelClass)
|
||||
}
|
||||
|
||||
private fun getModelClass(viewDescriptor: StructureViewDescriptor): Class<*>? {
|
||||
var model: Any = viewDescriptor.structureModel
|
||||
if (model is LogicalStructureViewModel) {
|
||||
val root = model.root
|
||||
if (root is LogicalStructureViewTreeElement<*>) {
|
||||
var assembledModel = root.getLogicalAssembledModel()
|
||||
val children = assembledModel.getChildren()
|
||||
if (children.size == 1)
|
||||
return children[0].model?.javaClass
|
||||
else
|
||||
return assembledModel.model?.javaClass
|
||||
}
|
||||
else {
|
||||
return root::class.java
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
}
|
||||
@@ -44,12 +44,12 @@ class PhysicalAndLogicalStructureViewBuilder(
|
||||
|
||||
return StructureViewComposite(
|
||||
StructureViewComposite.StructureViewDescriptor(
|
||||
StructureViewBundle.message("structureview.tab.logical"),
|
||||
StructureViewTab.LOGICAL.title,
|
||||
logicalBuilder.createStructureView(fileEditor, project),
|
||||
null
|
||||
),
|
||||
StructureViewComposite.StructureViewDescriptor(
|
||||
StructureViewBundle.message("structureview.tab.physical"),
|
||||
StructureViewTab.PHYSICAL.title,
|
||||
physicalBuilder.createStructureView(fileEditor, project),
|
||||
null
|
||||
)
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright 2000-2025 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
|
||||
package com.intellij.ide.structureView.logical
|
||||
|
||||
import com.intellij.ide.structureView.StructureViewBundle
|
||||
import org.jetbrains.annotations.ApiStatus
|
||||
|
||||
@ApiStatus.Internal
|
||||
enum class StructureViewTab(
|
||||
val title: String,
|
||||
) {
|
||||
PHYSICAL(StructureViewBundle.message("structureview.tab.physical")),
|
||||
LOGICAL(StructureViewBundle.message("structureview.tab.logical"));
|
||||
|
||||
companion object {
|
||||
fun ofTitle(title: String): StructureViewTab? = entries.firstOrNull { it.title == title }
|
||||
}
|
||||
|
||||
fun not(): StructureViewTab {
|
||||
return when (this) {
|
||||
PHYSICAL -> LOGICAL
|
||||
LOGICAL -> PHYSICAL
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package com.intellij.ide.structureView.logical.impl
|
||||
|
||||
import com.intellij.ide.TypePresentationService
|
||||
import com.intellij.ide.projectView.PresentationData
|
||||
import com.intellij.ide.structureView.StructureViewEventsCollector
|
||||
import com.intellij.ide.structureView.StructureViewModel
|
||||
import com.intellij.ide.structureView.StructureViewModelBase
|
||||
import com.intellij.ide.structureView.StructureViewTreeElement
|
||||
@@ -54,7 +55,11 @@ class LogicalStructureViewModel private constructor(psiFile: PsiFile, editor: Ed
|
||||
|
||||
override fun handleClick(element: StructureViewTreeElement, fragmentIndex: Int): Boolean {
|
||||
val model = getModel(element) ?: return false
|
||||
return LogicalModelPresentationProvider.getForObject(model)?.handleClick(model, fragmentIndex) ?: false
|
||||
val handled = LogicalModelPresentationProvider.getForObject(model)?.handleClick(model, fragmentIndex) ?: false
|
||||
if (handled) {
|
||||
StructureViewEventsCollector.logCustomClickHandled(model::class.java)
|
||||
}
|
||||
return handled
|
||||
}
|
||||
|
||||
private fun getModel(element: StructureViewTreeElement): Any? {
|
||||
@@ -213,6 +218,11 @@ private class ElementsBuilder {
|
||||
|
||||
override fun getLogicalAssembledModel() = assembledModel
|
||||
|
||||
override fun navigate(requestFocus: Boolean) {
|
||||
StructureViewEventsCollector.logNavigate(assembledModel.model!!::class.java)
|
||||
super<PsiTreeElementBase>.navigate(requestFocus)
|
||||
}
|
||||
|
||||
override fun equals(other: Any?): Boolean {
|
||||
if (other !is PsiElementStructureElement<*>) return false
|
||||
return assembledModel == other.assembledModel
|
||||
|
||||
Reference in New Issue
Block a user