File: timertop.cpp

package info (click to toggle)
gammaray 3.1.0%2Bds-3
  • links: PTS, VCS
  • area: main
  • in suites: trixie
  • size: 24,796 kB
  • sloc: cpp: 109,174; ansic: 2,156; sh: 336; python: 274; yacc: 90; lex: 82; xml: 61; makefile: 28; javascript: 9; ruby: 5
file content (134 lines) | stat: -rw-r--r-- 4,100 bytes parent folder | download | duplicates (2)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
/*
  timertop.cpp

  This file is part of GammaRay, the Qt application inspection and manipulation tool.

  SPDX-FileCopyrightText: 2010 Klarälvdalens Datakonsult AB, a KDAB Group company <info@kdab.com>
  Author: Thomas McGuire <thomas.mcguire@kdab.com>

  SPDX-License-Identifier: GPL-2.0-or-later

  Contact KDAB at <info@kdab.com> for commercial licensing options.
*/

#include "timertop.h"
#include "timermodel.h"

#include <core/objecttypefilterproxymodel.h>
#include <core/signalspycallbackset.h>

#include <common/objectbroker.h>
#include <common/objectid.h>

#include <QCoreApplication>
#include <QItemSelectionModel>
#include <QtPlugin>
#include <QThread>

using namespace GammaRay;

//
// TODO list for timer plugin
//

// BUG: QTimeLine class name not shown
// Related: Protect against timer deletion
// BUG: Only top-level timers are shown (bug in probe)

// ! Wakeup time for QTimers
// ! Add button to view object info
// ! Test timer added/removed at runtime
// Buttons to kill or slow down timer and start timer
// Add big fat "total wakeups / sec" label to the status bar
// Retrieve receiver name from connection model
// Add to view as column: receivers: slotXYZ and 3 others (shown in tooltip)
// Move signal hook to probe interface
// Then maybe add general signal profiler plugin, or even visualization
// Flash delegate when timer triggered
// Color cell in view redish, depending on how active the timer is

class TimerFilterModel : public ObjectTypeFilterProxyModel<QTimer>
{
public:
    explicit TimerFilterModel(QObject *parent)
        : ObjectTypeFilterProxyModel<QTimer>(parent)
    {
    }

    bool filterAcceptsObject(QObject *object) const override
    {
        if (object && object->inherits("QQmlTimer"))
            return true;
        return ObjectTypeFilterProxyModel<QTimer>::filterAcceptsObject(object);
    }
};

static bool processCallback()
{
    return TimerModel::isInitialized();
}

static void signal_begin_callback(QObject *caller, int method_index, void **argv)
{
    Q_UNUSED(argv);
    if (!processCallback())
        return;
    TimerModel::instance()->preSignalActivate(caller, method_index);
}

static void signal_end_callback(QObject *caller, int method_index)
{
    // NOTE: here and below the caller may be invalid, e.g. if it was deleted from a slot
    if (!processCallback())
        return;
    TimerModel::instance()->postSignalActivate(caller, method_index);
}

TimerTop::TimerTop(Probe *probe, QObject *parent)
    : TimerTopInterface(parent)
{
    Q_ASSERT(probe);

    QSortFilterProxyModel *const filterModel = new TimerFilterModel(this);
    filterModel->setDynamicSortFilter(true);
    filterModel->setSourceModel(probe->objectListModel());
    TimerModel::instance()->setParent(this); // otherwise it's not filtered out
    TimerModel::instance()->setSourceModel(filterModel);

    SignalSpyCallbackSet callbacks;
    callbacks.signalBeginCallback = signal_begin_callback;
    callbacks.signalEndCallback = signal_end_callback;
    probe->registerSignalSpyCallbackSet(callbacks);

    probe->registerModel(QStringLiteral("com.kdab.GammaRay.TimerModel"), TimerModel::instance());
    m_selectionModel = ObjectBroker::selectionModel(TimerModel::instance());

    connect(probe, &Probe::objectSelected, this, &TimerTop::objectSelected);
}

void TimerTop::clearHistory()
{
    TimerModel::instance()->clearHistory();
}

void TimerTop::objectSelected(QObject *obj)
{
    auto timer = qobject_cast<QTimer *>(obj);
    if (!timer)
        return;

    const auto model = m_selectionModel->model();
    const auto indexList = model->match(model->index(0, 0), ObjectModel::ObjectIdRole,
                                        QVariant::fromValue(ObjectId(timer)), 1,
                                        Qt::MatchExactly | Qt::MatchRecursive | Qt::MatchWrap);
    if (indexList.isEmpty())
        return;

    const auto &index = indexList.first();
    m_selectionModel->select(index, QItemSelectionModel::ClearAndSelect | QItemSelectionModel::Rows);
}

TimerTopFactory::TimerTopFactory(QObject *parent)
    : QObject(parent)
{
}