IJ-CR-155115 IJPL-172387 FUS: Add 'invocationPlace' parameter to dialogs statistic

Merge-request: IJ-MR-151127
Merged-by: Vera Petrenkova <Vera.Petrenkova@jetbrains.com>
(cherry picked from commit dbe25a3787fd283c2576bdb8ff4f8155a963d8f9)

GitOrigin-RevId: faf82a86cb8040b1d48b9ba2c2f9907767314c86
This commit is contained in:
Vera Petrenkova
2025-01-03 18:22:18 +00:00
committed by intellij-monorepo-bot
parent 769808c52d
commit ba81dfd08f
18 changed files with 228 additions and 47 deletions

View File

@@ -1961,6 +1961,7 @@ a:com.intellij.openapi.ui.MessageDialogBuilder
- pf:getDoNotAskOption():com.intellij.openapi.ui.DoNotAskOption
- pf:getHelpId():java.lang.String
- pf:getIcon():javax.swing.Icon
- pf:getInvocationPlace():java.lang.String
- pf:getMessage():java.lang.String
- pf:getNoText():java.lang.String
- pf:getParentComponent():java.awt.Component
@@ -1975,6 +1976,7 @@ a:com.intellij.openapi.ui.MessageDialogBuilder
- pf:setDoNotAskOption(com.intellij.openapi.ui.DoNotAskOption):V
- pf:setHelpId(java.lang.String):V
- pf:setIcon(javax.swing.Icon):V
- pf:setInvocationPlace(java.lang.String):V
- pf:setNoText(java.lang.String):V
- pf:setParentComponent(java.awt.Component):V
- pf:setProject(com.intellij.openapi.project.Project):V

View File

@@ -23,6 +23,7 @@ sealed class MessageDialogBuilder<T : MessageDialogBuilder<T>>(protected val tit
protected var icon: Icon? = null
protected var doNotAskOption: DoNotAskOption? = null
@NonNls protected var helpId: String? = null
@NonNls protected var invocationPlace: String? = null
protected abstract fun getThis(): T
@@ -85,6 +86,17 @@ sealed class MessageDialogBuilder<T : MessageDialogBuilder<T>>(protected val tit
return getThis()
}
/**
* Please provide invocation place to clarify the purpose of dialog in statistic.
* You should register your invocation place in plugin.xml as extension point
* See also: com.intellij.internal.statistic.collectors.fus.ui.InvocationPlaceEP
*/
@ApiStatus.Internal
fun invocationPlace(invocationPlace: @NonNls String): T {
this.invocationPlace = invocationPlace
return getThis()
}
class YesNo internal constructor(title: String, message: String) : MessageDialogBuilder<YesNo>(title, message) {
override fun getThis(): YesNo = this
@@ -106,8 +118,8 @@ sealed class MessageDialogBuilder<T : MessageDialogBuilder<T>>(protected val tit
val yesText = yesText ?: CommonBundle.getYesButtonText()
val noText = noText ?: CommonBundle.getNoButtonText()
return MessagesService.getInstance().showMessageDialog(
project = project, parentComponent = parentComponent, message = message, title = title, icon = icon,
options = arrayOf(yesText, noText), doNotAskOption = doNotAskOption, helpId = helpId, alwaysUseIdeaUI = true
project = project, parentComponent = parentComponent, message = message, title = title, options = arrayOf(yesText, noText),
icon = icon, doNotAskOption = doNotAskOption, alwaysUseIdeaUI = true, helpId = helpId, invocationPlace = invocationPlace,
) == YES
}
}
@@ -140,7 +152,7 @@ sealed class MessageDialogBuilder<T : MessageDialogBuilder<T>>(protected val tit
val options = arrayOf(yesText, noText, cancelText)
val choice = MessagesService.getInstance().showMessageDialog(
project = project, parentComponent = parentComponent, message = message, title = title, options = options,
icon = icon, doNotAskOption = doNotAskOption, helpId = helpId, alwaysUseIdeaUI = true)
icon = icon, doNotAskOption = doNotAskOption, alwaysUseIdeaUI = true, helpId = helpId, invocationPlace = invocationPlace)
return when (choice) {
0 -> YES
1 -> NO
@@ -179,7 +191,7 @@ sealed class MessageDialogBuilder<T : MessageDialogBuilder<T>>(protected val tit
val result = MessagesService.getInstance().showMessageDialog(
project = project, parentComponent = parentComponent, message = message, title = title, options = options,
defaultOptionIndex = defaultOptionIndex, focusedOptionIndex = focusedOptionIndex,
icon = icon, doNotAskOption = doNotAskOption, helpId = helpId, alwaysUseIdeaUI = true)
icon = icon, doNotAskOption = doNotAskOption, alwaysUseIdeaUI = true, helpId = helpId, invocationPlace = invocationPlace)
return if (result < 0) null else buttons[result]
}
}
@@ -200,6 +212,6 @@ class OkCancelDialogBuilder internal constructor(title: String, message: String)
val noText = noText ?: CommonBundle.getCancelButtonText()
return MessagesService.getInstance().showMessageDialog(
project = project, parentComponent = parentComponent, message = message, title = title, options = arrayOf(yesText, noText),
icon = icon, doNotAskOption = doNotAskOption, helpId = helpId, alwaysUseIdeaUI = true) == 0
icon = icon, doNotAskOption = doNotAskOption, alwaysUseIdeaUI = true, helpId = helpId, invocationPlace = invocationPlace) == 0
}
}

View File

@@ -33,17 +33,37 @@ interface MessagesService {
?: MessagesService::class.java.classLoader.loadClass("com.intellij.ui.messages.MessagesServiceImpl").getDeclaredConstructor().newInstance() as MessagesService
}
fun showMessageDialog(project: Project?,
parentComponent: Component? = null,
@DialogMessage message: String?,
@NlsContexts.DialogTitle title: String?,
options: Array<String>,
defaultOptionIndex: Int = 0,
focusedOptionIndex: Int = -1,
icon: Icon?,
doNotAskOption: DoNotAskOption?,
alwaysUseIdeaUI: Boolean = false,
helpId: String? = null): Int
fun showMessageDialog(
project: Project?,
parentComponent: Component? = null,
@DialogMessage message: String?,
@NlsContexts.DialogTitle title: String?,
options: Array<String>,
defaultOptionIndex: Int = 0,
focusedOptionIndex: Int = -1,
icon: Icon?,
doNotAskOption: DoNotAskOption?,
alwaysUseIdeaUI: Boolean = false,
helpId: String? = null
): Int {
return showMessageDialog(project, parentComponent, message, title, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption, alwaysUseIdeaUI, helpId, null)
}
fun showMessageDialog(
project: Project?,
parentComponent: Component? = null,
@DialogMessage message: String?,
@NlsContexts.DialogTitle title: String?,
options: Array<String>,
defaultOptionIndex: Int = 0,
focusedOptionIndex: Int = -1,
icon: Icon?,
doNotAskOption: DoNotAskOption?,
alwaysUseIdeaUI: Boolean = false,
helpId: String? = null,
invocationPlace: String? = null
): Int
fun showMoreInfoMessageDialog(project: Project?,
@DialogMessage message: String?,

View File

@@ -4177,6 +4177,7 @@ Fc:com.intellij.openapi.ui.Messages
- s:showDialog(com.intellij.openapi.project.Project,java.lang.String,java.lang.String,java.lang.String[],I,javax.swing.Icon,com.intellij.openapi.ui.DialogWrapper$DoNotAskOption):I
- s:showDialog(java.awt.Component,java.lang.String,java.lang.String,java.lang.String[],I,javax.swing.Icon):I
- s:showDialog(java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DialogWrapper$DoNotAskOption):I
- s:showDialog(java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DialogWrapper$DoNotAskOption,java.lang.String):I
- s:showDialog(java.lang.String,java.lang.String,java.lang.String[],I,javax.swing.Icon):I
- s:showDialog(java.lang.String,java.lang.String,java.lang.String[],I,javax.swing.Icon,com.intellij.openapi.ui.DialogWrapper$DoNotAskOption):I
- s:showEditableChooseDialog(java.lang.String,java.lang.String,javax.swing.Icon,java.lang.String[],java.lang.String,com.intellij.openapi.ui.InputValidator):java.lang.String
@@ -4607,10 +4608,12 @@ c:com.intellij.openapi.ui.messages.MessageDialog
- p:<init>(com.intellij.openapi.project.Project):V
- <init>(com.intellij.openapi.project.Project,java.awt.Component,java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DoNotAskOption,Z):V
- <init>(com.intellij.openapi.project.Project,java.awt.Component,java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DoNotAskOption,Z,java.lang.String):V
- <init>(com.intellij.openapi.project.Project,java.awt.Component,java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DoNotAskOption,Z,java.lang.String,java.lang.String):V
- <init>(com.intellij.openapi.project.Project,java.lang.String,java.lang.String,java.lang.String[],I,javax.swing.Icon,Z):V
- <init>(com.intellij.openapi.project.Project,Z):V
- <init>(java.lang.String,java.lang.String,java.lang.String[],I,javax.swing.Icon):V
- p:_init(java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DoNotAskOption,java.lang.String):V
- p:_init(java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DoNotAskOption,java.lang.String,java.lang.String):V
- p:createActions():javax.swing.Action[]
- p:createCenterPanel():javax.swing.JComponent
- p:createIconPanel():javax.swing.JPanel

View File

@@ -22,11 +22,11 @@ interface FeatureUsageUiEvents {
fun logResetConfigurable(configurable: Configurable)
fun logShowDialog(dialogClass: Class<*>)
fun logShowDialog(dialogClass: Class<*>, invocationPlace: String? = null)
fun logCloseDialog(dialogClass: Class<*>, exitCode: Int)
fun logCloseDialog(dialogClass: Class<*>, exitCode: Int, invocationPlace: String? = null)
fun logClickOnHelpDialog(dialogClass: Class<*>)
fun logClickOnHelpDialog(dialogClass: Class<*>, invocationPlace: String? = null)
}
@ApiStatus.Internal
@@ -40,12 +40,12 @@ object EmptyFeatureUsageUiEvents : FeatureUsageUiEvents {
override fun logResetConfigurable(configurable: Configurable) {
}
override fun logShowDialog(dialogClass: Class<*>) {
override fun logShowDialog(dialogClass: Class<*>, invocationPlace: String?) {
}
override fun logCloseDialog(dialogClass: Class<*>, exitCode: Int) {
override fun logCloseDialog(dialogClass: Class<*>, exitCode: Int, invocationPlace: String?) {
}
override fun logClickOnHelpDialog(dialogClass: Class<*>) {
override fun logClickOnHelpDialog(dialogClass: Class<*>, invocationPlace: String?) {
}
}

View File

@@ -50,8 +50,8 @@ import java.awt.event.*;
import java.beans.PropertyChangeListener;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.util.List;
import java.util.*;
import java.util.List;
import java.util.function.Function;
import java.util.stream.IntStream;
@@ -197,6 +197,7 @@ public abstract class DialogWrapper {
private int myValidationDelay = 300;
private boolean myValidationStarted;
private boolean myKeepPopupsOpen;
@Nls private @NonNls @Nullable String invocationPlace = null;
protected Action myOKAction;
protected Action myCancelAction;
@@ -1865,20 +1866,20 @@ public abstract class DialogWrapper {
private void logCloseDialogEvent(int exitCode) {
boolean canRecord = canRecordDialogId();
if (canRecord) {
FeatureUsageUiEventsKt.getUiEventLogger().logCloseDialog(getClass(), exitCode);
FeatureUsageUiEventsKt.getUiEventLogger().logCloseDialog(getClass(), exitCode, invocationPlace);
}
}
private void logShowDialogEvent() {
boolean canRecord = canRecordDialogId();
if (canRecord) {
FeatureUsageUiEventsKt.getUiEventLogger().logShowDialog(getClass());
FeatureUsageUiEventsKt.getUiEventLogger().logShowDialog(getClass(), invocationPlace);
}
}
private void logClickOnHelpDialogEvent() {
if (!canRecordDialogId()) return;
FeatureUsageUiEventsKt.getUiEventLogger().logClickOnHelpDialog(getClass());
FeatureUsageUiEventsKt.getUiEventLogger().logClickOnHelpDialog(getClass(), invocationPlace);
}
/**
@@ -1888,6 +1889,11 @@ public abstract class DialogWrapper {
return true;
}
@ApiStatus.Internal
public void setInvocationPlace(@Nullable @NonNls String invocationPlace) {
this.invocationPlace = invocationPlace;
}
/**
* Base class for dialog wrapper actions that need to ensure that only
* one action for the dialog is running.

View File

@@ -274,6 +274,25 @@ public class Messages {
.showMessageDialog(null, null, message, title, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption, false, null);
}
/**
* Use this method only if you do not know project or component
*
* @return number of button pressed: from 0 up to options.length-1 inclusive, or -1 for Cancel
* @see #showDialog(Project, String, String, String[], int, Icon, DialogWrapper.DoNotAskOption)
* @see #showDialog(Component, String, String, String[], int, Icon)
*/
public static int showDialog(@DialogMessage String message,
@NotNull @DialogTitle String title,
String @NotNull @NlsContexts.Button [] options,
int defaultOptionIndex,
int focusedOptionIndex,
@Nullable Icon icon,
@Nullable DialogWrapper.DoNotAskOption doNotAskOption,
@Nullable String invocationPlace) {
return MessagesService.getInstance()
.showMessageDialog(null, null, message, title, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption, false, null, invocationPlace);
}
/**
* Use this method only if you do not know project or component
*

View File

@@ -59,9 +59,24 @@ public class MessageDialog extends DialogWrapper {
@Nullable Icon icon,
@Nullable com.intellij.openapi.ui.DoNotAskOption doNotAskOption,
boolean canBeParent,
@Nullable String helpId) {
@Nullable String helpId,
@Nullable String invocationPlace) {
super(project, parentComponent, canBeParent, IdeModalityType.IDE);
_init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption, helpId);
_init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption, helpId, invocationPlace);
}
public MessageDialog(@Nullable Project project,
@Nullable Component parentComponent,
@NlsContexts.DialogMessage @Nullable String message,
@NlsContexts.DialogTitle String title,
String @NotNull [] options,
int defaultOptionIndex,
int focusedOptionIndex,
@Nullable Icon icon,
@Nullable com.intellij.openapi.ui.DoNotAskOption doNotAskOption,
boolean canBeParent,
@Nullable String helpId) {
this(project, parentComponent, message, title, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption, canBeParent, helpId, null);
}
public MessageDialog(@NlsContexts.DialogMessage @Nullable String message,
@@ -92,6 +107,18 @@ public class MessageDialog extends DialogWrapper {
@Nullable Icon icon,
@Nullable com.intellij.openapi.ui.DoNotAskOption doNotAskOption,
@Nullable String helpId) {
_init(title, message, options, defaultOptionIndex, focusedOptionIndex, icon, doNotAskOption, helpId, null);
}
protected void _init(@NlsContexts.DialogTitle String title,
@NlsContexts.DialogMessage @Nullable String message,
String @NotNull [] options,
int defaultOptionIndex,
int focusedOptionIndex,
@Nullable Icon icon,
@Nullable com.intellij.openapi.ui.DoNotAskOption doNotAskOption,
@Nullable String helpId,
@Nullable String invocationPlace) {
setTitle(title);
myMessage = message;
myOptions = options;
@@ -100,6 +127,7 @@ public class MessageDialog extends DialogWrapper {
myIcon = icon;
myHelpId = helpId;
setDoNotAskOption(doNotAskOption);
setInvocationPlace(invocationPlace);
init();
}

View File

@@ -16282,7 +16282,7 @@ c:com.intellij.ui.messages.MessagesServiceImpl
- showErrorDialog(com.intellij.openapi.project.Project,java.lang.String,java.lang.String):V
- showInputDialog(com.intellij.openapi.project.Project,java.awt.Component,java.lang.String,java.lang.String,javax.swing.Icon,java.lang.String,com.intellij.openapi.ui.InputValidator,com.intellij.openapi.util.TextRange,java.lang.String):java.lang.String
- showInputDialogWithCheckBox(java.lang.String,java.lang.String,java.lang.String,Z,Z,javax.swing.Icon,java.lang.String,com.intellij.openapi.ui.InputValidator):com.intellij.openapi.util.Pair
- showMessageDialog(com.intellij.openapi.project.Project,java.awt.Component,java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DoNotAskOption,Z,java.lang.String):I
- showMessageDialog(com.intellij.openapi.project.Project,java.awt.Component,java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon,com.intellij.openapi.ui.DoNotAskOption,Z,java.lang.String,java.lang.String):I
- showMoreInfoMessageDialog(com.intellij.openapi.project.Project,java.lang.String,java.lang.String,java.lang.String,java.lang.String[],I,I,javax.swing.Icon):I
- showMultilineInputDialog(com.intellij.openapi.project.Project,java.lang.String,java.lang.String,java.lang.String,javax.swing.Icon,com.intellij.openapi.ui.InputValidator):java.lang.String
- showPasswordDialog(com.intellij.openapi.project.Project,java.lang.String,java.lang.String,javax.swing.Icon,com.intellij.openapi.ui.InputValidator):java.lang.String

View File

@@ -0,0 +1,16 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.internal.statistic.collectors.fus.ui
import com.intellij.openapi.extensions.RequiredElement
import com.intellij.util.xmlb.annotations.Attribute
import org.jetbrains.annotations.ApiStatus
/**
* Extension point to register an invocation place ID for a dialog to record in feature usage statistics.
*/
@ApiStatus.Internal
internal class DialogInvocationPlaceEP {
@Attribute("id")
@RequiredElement
var id: String? = null
}

View File

@@ -0,0 +1,47 @@
// Copyright 2000-2024 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license.
package com.intellij.internal.statistic.collectors.fus.ui
import com.intellij.internal.statistic.utils.getPluginInfoByDescriptor
import com.intellij.openapi.components.Service
import com.intellij.openapi.components.service
import com.intellij.openapi.extensions.ExtensionPointListener
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.extensions.PluginDescriptor
import com.intellij.util.application
import kotlinx.collections.immutable.toImmutableList
import java.util.concurrent.ConcurrentSkipListSet
@Service(Service.Level.APP)
internal class DialogInvocationPlacesCollector private constructor() {
private val invocationPlaces: MutableSet<String> = ConcurrentSkipListSet()
init {
processExtensions()
}
companion object {
@JvmStatic
fun getInstance(): DialogInvocationPlacesCollector = application.service()
private val EP_NAME: ExtensionPointName<DialogInvocationPlaceEP> = ExtensionPointName("com.intellij.dialogInvocationPlace")
}
private fun processExtensions() {
EP_NAME.processWithPluginDescriptor { extension, pluginDescriptor ->
addInvocationPlace(extension, pluginDescriptor)
}
EP_NAME.addExtensionPointListener(object : ExtensionPointListener<DialogInvocationPlaceEP> {
override fun extensionAdded(extension: DialogInvocationPlaceEP, pluginDescriptor: PluginDescriptor) {
addInvocationPlace(extension, pluginDescriptor)
}
}, null)
}
private fun addInvocationPlace(extension: DialogInvocationPlaceEP, pluginDescriptor: PluginDescriptor) {
val info = getPluginInfoByDescriptor(pluginDescriptor)
if (info.isSafeToReport() && extension.id != null) {
invocationPlaces.add(extension.id!!)
}
}
fun getInvocationPlaces(): List<String> = invocationPlaces.toImmutableList()
}

View File

@@ -5,14 +5,18 @@ import com.intellij.internal.statistic.eventLog.EventLogGroup
import com.intellij.internal.statistic.eventLog.FeatureUsageData
import com.intellij.internal.statistic.eventLog.FeatureUsageUiEvents
import com.intellij.internal.statistic.eventLog.events.*
import com.intellij.internal.statistic.eventLog.events.EventFields.StringValidatedByCustomRule
import com.intellij.internal.statistic.eventLog.fus.FeatureUsageLogger
import com.intellij.internal.statistic.eventLog.validator.ValidationResultType
import com.intellij.internal.statistic.eventLog.validator.rules.EventContext
import com.intellij.internal.statistic.eventLog.validator.rules.impl.CustomValidationRule
import com.intellij.internal.statistic.service.fus.collectors.CounterUsagesCollector
import com.intellij.openapi.options.Configurable
import com.intellij.openapi.options.ex.ConfigurableWrapper
import com.intellij.openapi.ui.DialogWrapper
internal object DialogsCounterUsagesCollector : CounterUsagesCollector() {
private val GROUP = EventLogGroup("ui.dialogs", 61)
private val GROUP = EventLogGroup("ui.dialogs", 62)
val EXIT_CODE: PrimitiveEventField<Int> = object: PrimitiveEventField<Int>() {
override val name: String = "code"
@@ -34,16 +38,26 @@ internal object DialogsCounterUsagesCollector : CounterUsagesCollector() {
}
val DIALOG_CLASS: ClassEventField = EventFields.Class("dialog_class")
val INVOCATION_PLACE: StringEventField = StringValidatedByCustomRule("dialog_invocation_place", ListValidationRule::class.java)
val SHOW: VarargEventId = GROUP.registerVarargEvent("show", DIALOG_CLASS, EventFields.PluginInfo)
val CLOSE: VarargEventId = GROUP.registerVarargEvent("close", DIALOG_CLASS, EXIT_CODE, EventFields.PluginInfo)
val HELP: VarargEventId = GROUP.registerVarargEvent("help.clicked", DIALOG_CLASS, EventFields.PluginInfo)
val SHOW: VarargEventId = GROUP.registerVarargEvent("show", DIALOG_CLASS, INVOCATION_PLACE, EventFields.PluginInfo)
val CLOSE: VarargEventId = GROUP.registerVarargEvent("close", DIALOG_CLASS, INVOCATION_PLACE, EXIT_CODE, EventFields.PluginInfo)
val HELP: VarargEventId = GROUP.registerVarargEvent("help.clicked", DIALOG_CLASS, INVOCATION_PLACE, EventFields.PluginInfo)
override fun getGroup(): EventLogGroup = GROUP
}
internal class ListValidationRule : CustomValidationRule() {
override fun getRuleId(): String = "dialog_invocation_place"
override fun doValidate(data: String, context: EventContext): ValidationResultType {
val invocationPlaces = DialogInvocationPlacesCollector.getInstance().getInvocationPlaces()
if (invocationPlaces.contains(data)) return ValidationResultType.ACCEPTED
return ValidationResultType.REJECTED
}
}
internal object SettingsCounterUsagesCollector : CounterUsagesCollector() {
private val GROUP = EventLogGroup("ui.settings", 62)
private val GROUP = EventLogGroup("ui.settings", 63)
private val CONFIGURABLE_CLASS = EventFields.Class("configurable")
val SELECT: EventId3<Class<*>?, Boolean, Long> = GROUP.registerEvent("select",
@@ -94,24 +108,27 @@ internal class FeatureUsageUiEventsImpl : FeatureUsageUiEvents {
event.log(wrapper?.project, (wrapper?.configurable ?: configurable)::class.java)
}
override fun logShowDialog(clazz: Class<*>) {
override fun logShowDialog(clazz: Class<*>, invocationPlace: String?) {
if (FeatureUsageLogger.getInstance().isEnabled()) {
DialogsCounterUsagesCollector.SHOW.log(DialogsCounterUsagesCollector.DIALOG_CLASS.with(clazz))
DialogsCounterUsagesCollector.SHOW.log(DialogsCounterUsagesCollector.DIALOG_CLASS.with(clazz),
DialogsCounterUsagesCollector.INVOCATION_PLACE.with(invocationPlace))
}
}
override fun logCloseDialog(clazz: Class<*>, exitCode: Int) {
override fun logCloseDialog(clazz: Class<*>, exitCode: Int, invocationPlace: String?) {
if (FeatureUsageLogger.getInstance().isEnabled()) {
DialogsCounterUsagesCollector.CLOSE.log(
DialogsCounterUsagesCollector.DIALOG_CLASS.with(clazz),
DialogsCounterUsagesCollector.INVOCATION_PLACE.with(invocationPlace),
DialogsCounterUsagesCollector.EXIT_CODE.with(exitCode)
)
}
}
override fun logClickOnHelpDialog(clazz: Class<*>) {
override fun logClickOnHelpDialog(clazz: Class<*>, invocationPlace: String?) {
if (FeatureUsageLogger.getInstance().isEnabled()) {
DialogsCounterUsagesCollector.HELP.log(DialogsCounterUsagesCollector.DIALOG_CLASS.with(clazz))
DialogsCounterUsagesCollector.HELP.log(DialogsCounterUsagesCollector.DIALOG_CLASS.with(clazz),
DialogsCounterUsagesCollector.INVOCATION_PLACE.with(invocationPlace))
}
}
}

View File

@@ -85,6 +85,7 @@ import com.intellij.util.io.delete
import com.intellij.workspaceModel.ide.impl.jpsMetrics
import kotlinx.coroutines.*
import org.jetbrains.annotations.ApiStatus.Internal
import org.jetbrains.annotations.NonNls
import org.jetbrains.annotations.TestOnly
import org.jetbrains.annotations.VisibleForTesting
import java.io.IOException
@@ -1385,17 +1386,21 @@ private suspend fun confirmOpenNewProject(options: OpenProjectTask): Int {
val openInExistingFrame = withContext(Dispatchers.EDT) {
// readAction is not enough
writeIntentReadAction {
@NonNls
val actionPlace = "Open project action"
if (options.isNewProject)
MessageDialogBuilder.yesNoCancel(ideUICustomization.projectMessage("title.new.project"), message)
.yesText(IdeBundle.message("button.existing.frame"))
.noText(IdeBundle.message("button.new.frame"))
.doNotAsk(ProjectNewWindowDoNotAskOption())
.invocationPlace(actionPlace)
.guessWindowAndAsk()
else
MessageDialogBuilder.yesNoCancel(ideUICustomization.projectMessage("title.open.project"), message)
.yesText(IdeBundle.message("button.existing.frame"))
.noText(IdeBundle.message("button.new.frame"))
.doNotAsk(ProjectNewWindowDoNotAskOption())
.invocationPlace(actionPlace)
.guessWindowAndAsk()
}
}

View File

@@ -63,9 +63,10 @@ internal class AlertMessagesManager {
focusedOptionIndex: Int,
icon: Icon?,
doNotAskOption: DoNotAskOption?,
helpId: String?): Int {
helpId: String?,
invocationPlace: String?): Int {
val dialog = AlertDialog(project, parentComponent, message, title, options, defaultOptionIndex, focusedOptionIndex, getIcon(icon),
doNotAskOption, helpId)
doNotAskOption, helpId, invocationPlace)
AppIcon.getInstance().requestAttention(project, true)
dialog.show()
return dialog.exitCode
@@ -100,7 +101,8 @@ class AlertDialog(project: Project?,
val myFocusedOptionIndex: Int,
icon: Icon,
doNotAskOption: com.intellij.openapi.ui.DoNotAskOption?,
val myHelpId: String?) : DialogWrapper(project, parentComponent, false, IdeModalityType.IDE, false) {
val myHelpId: String?,
invocationPlace: String? = null) : DialogWrapper(project, parentComponent, false, IdeModalityType.IDE, false) {
private val myIsTitleComponent = SystemInfoRt.isMac || !Registry.`is`("ide.message.dialogs.as.swing.alert.show.title.bar", false)
@@ -117,6 +119,7 @@ class AlertDialog(project: Project?,
init {
title = myTitle
setDoNotAskOption(doNotAskOption)
setInvocationPlace(invocationPlace)
if (myIsTitleComponent && !SystemInfoRt.isMac) {
myCloseButton = object : InplaceButton(IconButton(null, AllIcons.Windows.CloseActive, null, null), {

View File

@@ -44,7 +44,8 @@ public class MessagesServiceImpl implements MessagesService {
@Nullable Icon icon,
@Nullable DoNotAskOption doNotAskOption,
boolean alwaysUseIdeaUI,
@Nullable String helpId) {
@Nullable String helpId,
@Nullable String invocationPlace) {
if (isApplicationInUnitTestOrHeadless()) {
return TestDialogManager.getTestImplementation().show(message);
}
@@ -52,11 +53,11 @@ public class MessagesServiceImpl implements MessagesService {
AlertMessagesManager alertMessagesManager = AlertMessagesManager.getInstanceIfPossible();
if (alertMessagesManager != null) {
return alertMessagesManager.showMessageDialog(project, parentComponent, message, title, options, defaultOptionIndex,
focusedOptionIndex, icon, doNotAskOption, helpId);
focusedOptionIndex, icon, doNotAskOption, helpId, invocationPlace);
}
MessageDialog dialog = new MessageDialog(project, parentComponent, message, title, options, defaultOptionIndex, focusedOptionIndex,
icon, doNotAskOption, false, helpId);
icon, doNotAskOption, false, helpId, invocationPlace);
dialog.show();
return dialog.getExitCode();
}
@@ -79,7 +80,7 @@ public class MessagesServiceImpl implements MessagesService {
AlertMessagesManager alertMessagesManager = AlertMessagesManager.getInstanceIfPossible();
if (alertMessagesManager != null) {
return alertMessagesManager.showMessageDialog(project, null, message, title, options, defaultOptionIndex,
focusedOptionIndex, icon, null, null);
focusedOptionIndex, icon, null, null, null);
}
}

View File

@@ -1238,6 +1238,7 @@
<statistics.validation.customValidationRule
implementation="com.intellij.openapi.wm.impl.status.widget.StatusBarWidgetUsagesCollector$StatusBarWidgetFactoryValidationRule"/>
<statistics.validation.customValidationRule implementation="com.intellij.usages.impl.ScopeRuleValidator"/>
<statistics.validation.customValidationRule implementation="com.intellij.internal.statistic.collectors.fus.ui.ListValidationRule"/>
<statistic.eventLog.eventLoggerProvider implementation="com.intellij.internal.statistic.IJMapperEventLoggerProvider"/>
<statistics.applicationUsagesCollector implementation="com.intellij.internal.statistic.eventLog.IJFUSMapper"/>

View File

@@ -189,7 +189,7 @@
<extensionPoint name="toolWindowAllowlist" beanClass="com.intellij.openapi.wm.ToolWindowAllowlistEP" dynamic="true"/>
<extensionPoint name="statistics.gotItTooltipAllowlist" beanClass="com.intellij.internal.statistic.collectors.fus.ui.GotItTooltipAllowlistEP" dynamic="true"/>
<extensionPoint name="dialogInvocationPlace" beanClass="com.intellij.internal.statistic.collectors.fus.ui.DialogInvocationPlaceEP" dynamic="true"/>
<extensionPoint name="library.toolWindow" beanClass="com.intellij.openapi.wm.ext.LibraryDependentToolWindow" dynamic="true">
<with attribute="librarySearchClass" implements="com.intellij.openapi.wm.ext.LibrarySearchHelper"/>
<with attribute="factoryClass" implements="com.intellij.openapi.wm.ToolWindowFactory"/>

View File

@@ -522,6 +522,7 @@
serviceImplementation="com.intellij.internal.statistic.collectors.fus.actions.persistence.ActionsCollectorImpl"/>
<applicationService serviceInterface="com.intellij.internal.statistic.eventLog.FeatureUsageUiEvents"
serviceImplementation="com.intellij.internal.statistic.collectors.fus.ui.FeatureUsageUiEventsImpl"/>
<dialogInvocationPlace id="Open project action"/>
<applicationService serviceInterface="com.intellij.ide.plugins.PluginInfoProvider"
serviceImplementation="com.intellij.ide.plugins.marketplace.MarketplaceRequests"
preload="true"/>