QmlDesigner: Collect events for telemetry plugin

For each action/event we want to track we
emit QmlDesignerPlugin::usageStatisticsNotifier() with an identifer.

This allows counting how many states, transitions, timelines were created
and we track every registered action.

More 'trace points' can be added later.

Change-Id: Ibb31e1b7e20d984a10697e05bb4417e7ad1b8980
Reviewed-by: Miikka Heikkinen <miikka.heikkinen@qt.io>
Reviewed-by: Mahmoud Badri <mahmoud.badri@qt.io>
Reviewed-by: Thomas Hartmann <thomas.hartmann@qt.io>
This commit is contained in:
Thomas Hartmann
2020-11-11 17:33:35 +01:00
parent 093d5f5ab1
commit fb9fb01e34
10 changed files with 50 additions and 6 deletions

View File

@@ -29,6 +29,10 @@
#include "annotation.h"
#include "qmlmodelnodeproxy.h"
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
#include <coreplugin/icore.h>
#include <QObject>
@@ -175,6 +179,7 @@ void AnnotationEditor::removeFullAnnotation()
void AnnotationEditor::acceptedClicked()
{
if (m_dialog) {
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_ANNOTATION_ADDED);
QString customId = m_dialog->customId();
Annotation annotation = m_dialog->annotation();

View File

@@ -343,7 +343,7 @@ public:
parentNode = selectionContext().currentSingleSelectedNode().parentProperty().parentModelNode();
if (!ModelNode::isThisOrAncestorLocked(parentNode)) {
ActionTemplate *selectionAction = new ActionTemplate(QString(), &ModelNodeOperations::select);
ActionTemplate *selectionAction = new ActionTemplate("SELECTION", {}, &ModelNodeOperations::select);
selectionAction->setParent(menu());
selectionAction->setText(QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select parent: %1")).arg(
captionForModelNode(parentNode)));
@@ -363,7 +363,7 @@ public:
&& !ModelNode::isThisOrAncestorLocked(node)) {
selectionContext().setTargetNode(node);
QString what = QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Select: %1")).arg(captionForModelNode(node));
ActionTemplate *selectionAction = new ActionTemplate(what, &ModelNodeOperations::select);
ActionTemplate *selectionAction = new ActionTemplate("SELECT", what, &ModelNodeOperations::select);
SelectionContext nodeSelectionContext = selectionContext();
nodeSelectionContext.setTargetNode(node);
@@ -546,7 +546,7 @@ public:
for (const QmlFlowItemNode &node : QmlFlowViewNode(selectionContext().rootNode()).flowItems()) {
if (node != selectionContext().currentSingleSelectedNode().parentProperty().parentModelNode()) {
QString what = QString(QT_TRANSLATE_NOOP("QmlDesignerContextMenu", "Connect: %1")).arg(captionForModelNode(node));
ActionTemplate *connectionAction = new ActionTemplate(what, &ModelNodeOperations::addTransition);
ActionTemplate *connectionAction = new ActionTemplate("CONNECT", what, &ModelNodeOperations::addTransition);
SelectionContext nodeSelectionContext = selectionContext();
nodeSelectionContext.setTargetNode(node);

View File

@@ -29,6 +29,7 @@
#include "abstractaction.h"
#include "abstractactiongroup.h"
#include "qmlitemnode.h"
#include <qmldesignerplugin.h>
#include <coreplugin/actionmanager/command.h>
@@ -103,17 +104,19 @@ class ActionTemplate : public DefaultAction
{
public:
ActionTemplate(const QString &description, SelectionContextOperation action)
: DefaultAction(description), m_action(action)
ActionTemplate(const QByteArray &id, const QString &description, SelectionContextOperation action)
: DefaultAction(description), m_action(action), m_id(id)
{ }
void actionTriggered(bool b) override
{
QmlDesignerPlugin::emitUsageStatisticsContextAction(QString::fromUtf8(m_id));
m_selectionContext.setToggled(b);
m_action(m_selectionContext);
}
SelectionContextOperation m_action;
QByteArray m_id;
};
class ActionGroup : public AbstractActionGroup
@@ -202,7 +205,7 @@ public:
SelectionContextOperation selectionAction,
SelectionContextPredicate enabled = &SelectionContextFunctors::always,
SelectionContextPredicate visibility = &SelectionContextFunctors::always) :
AbstractAction(new ActionTemplate(description, selectionAction)),
AbstractAction(new ActionTemplate(id, description, selectionAction)),
m_id(id),
m_category(category),
m_priority(priority),

View File

@@ -572,6 +572,7 @@ void ItemLibraryWidget::addResources()
for (const AddResourceHandler &handler : handlers) {
QStringList fileNames = partitionedFileNames.values(category);
if (handler.category == category) {
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_RESOURCE_IMPORTED + category);
if (!handler.operation(fileNames, document->fileName().parentDir().toString()))
Core::AsynchronousMessageBox::warning(tr("Failed to Add Files"), tr("Could not add %1 to project.").arg(fileNames.join(" ")));
break;

View File

@@ -40,6 +40,8 @@
#include <variantproperty.h>
#include <nodelistproperty.h>
#include <qmldesignerconstants.h>
#include <qmldesignerplugin.h>
#include <qmlitemnode.h>
#include <qmlstate.h>
#include <annotationeditor/annotationeditor.h>
@@ -182,6 +184,8 @@ void StatesEditorView::addState()
if (!QmlVisualNode::isValidQmlVisualNode(rootModelNode()))
return;
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_STATE_ADDED);
QStringList modelStateNames = rootStateGroup().names();
QString newStateName;

View File

@@ -44,6 +44,7 @@
#include <rewritertransaction.h>
#include <variantproperty.h>
#include <viewmanager.h>
#include <qmldesignerconstants.h>
#include <qmldesignericons.h>
#include <qmldesignerplugin.h>
#include <qmlitemnode.h>
@@ -304,6 +305,8 @@ const QmlTimeline TimelineView::addNewTimeline()
QTC_ASSERT(isAttached(), return QmlTimeline());
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TIMELINE_ADDED);
try {
ensureQtQuickTimelineImport();
} catch (const Exception &e) {

View File

@@ -40,6 +40,7 @@
#include <rewritertransaction.h>
#include <variantproperty.h>
#include <viewmanager.h>
#include <qmldesignerconstants.h>
#include <qmldesignericons.h>
#include <qmldesignerplugin.h>
#include <qmlitemnode.h>
@@ -203,6 +204,8 @@ ModelNode TransitionEditorView::addNewTransition()
states = QmlVisualNode(root).states().allStates();
}
QmlDesignerPlugin::emitUsageStatistics(Constants::EVENT_TRANSITION_ADDED);
if (states.isEmpty()) {
Core::AsynchronousMessageBox::warning(tr("No States Defined"),
tr("There are no states defined in this component."));

View File

@@ -77,6 +77,13 @@ const char M_VIEW_WORKSPACES[] = "QmlDesigner.Menu.View.Workspaces";
const int MODELNODE_PREVIEW_IMAGE_DIMENSIONS = 150;
const char EVENT_TIMELINE_ADDED[] = "Timeline Added";
const char EVENT_TRANSITION_ADDED[] = "Transition Added";
const char EVENT_STATE_ADDED[] = "State Added";
const char EVENT_ANNOTATION_ADDED[] = "Annotation Added";
const char EVENT_RESOURCE_IMPORTED[] = "Resource Imported ";
const char EVENT_ACTION_EXECUTED[] = "Action Executed ";
namespace Internal {
enum { debug = 0 };
}

View File

@@ -547,6 +547,17 @@ double QmlDesignerPlugin::formEditorDevicePixelRatio()
return topLevelWindows.constFirst()->screen()->devicePixelRatio();
}
void QmlDesignerPlugin::emitUsageStatistics(const QString &identifier)
{
QTC_ASSERT(instance(), return);
emit instance()->usageStatisticsNotifier(identifier);
}
void QmlDesignerPlugin::emitUsageStatisticsContextAction(const QString &identifier)
{
emitUsageStatistics(Constants::EVENT_ACTION_EXECUTED + identifier);
}
QmlDesignerPlugin *QmlDesignerPlugin::instance()
{
return m_instance;

View File

@@ -82,6 +82,13 @@ public:
static double formEditorDevicePixelRatio();
static void emitUsageStatistics(const QString &identifier);
static void emitUsageStatisticsContextAction(const QString &identifier);
signals:
void usageStatisticsNotifier(const QString &identifier);
private: // functions
void integrateIntoQtCreator(QWidget *modeWidget);
void showDesigner();