VirtualBox

Changeset 103460 in vbox


Ignore:
Timestamp:
Feb 19, 2024 9:17:15 PM (11 months ago)
Author:
vboxsync
Message:

VBoxDbg: Added some simple sub-tree filtering to the statistics viewer. bugref:10376

Location:
trunk/src/VBox/Debugger
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Debugger/VBoxDbgStatsQt.cpp

    r103403 r103460  
    3333#include "VBoxDbgStatsQt.h"
    3434
    35 #include <QLocale>
    36 #include <QPushButton>
    37 #include <QSpinBox>
    38 #include <QLabel>
     35#include <QAction>
     36#include <QApplication>
    3937#include <QCheckBox>
    4038#include <QClipboard>
    41 #include <QApplication>
     39#include <QContextMenuEvent>
     40#include <QDialog>
     41#include <QDialogButtonBox>
     42#include <QGroupBox>
     43#include <QGridLayout>
    4244#include <QHBoxLayout>
     45#include <QHeaderView>
     46#include <QKeySequence>
     47#include <QLabel>
     48#include <QLineEdit>
     49#include <QLocale>
     50#include <QMessageBox>
     51#include <QPushButton>
     52#include <QSortFilterProxyModel>
     53#include <QSpinBox>
    4354#include <QVBoxLayout>
    44 #include <QKeySequence>
    45 #include <QAction>
    46 #include <QContextMenuEvent>
    47 #include <QHeaderView>
    48 #include <QSortFilterProxyModel>
    4955
    5056#include <iprt/errcore.h>
     
    104110
    105111/**
     112 * Filtering data.
     113 */
     114typedef struct VBoxGuiStatsFilterData
     115{
     116    /** Number of instances. */
     117    static uint32_t volatile s_cInstances;
     118    uint64_t            uMinValue;
     119    uint64_t            uMaxValue;
     120    QRegularExpression *pRegexName;
     121
     122    VBoxGuiStatsFilterData()
     123        : uMinValue(0)
     124        , uMaxValue(UINT64_MAX)
     125        , pRegexName(NULL)
     126    {
     127        s_cInstances += 1;
     128    }
     129
     130    ~VBoxGuiStatsFilterData()
     131    {
     132        if (pRegexName)
     133        {
     134            delete pRegexName;
     135            pRegexName = NULL;
     136        }
     137        s_cInstances -= 1;
     138    }
     139
     140    bool isAllDefaults(void) const
     141    {
     142        return (uMinValue == 0 || uMinValue == UINT64_MAX)
     143            && (uMaxValue == 0 || uMaxValue == UINT64_MAX)
     144            && pRegexName == NULL;
     145    }
     146} VBoxGuiStatsFilterData;
     147
     148
     149/**
    106150 * A tree node representing a statistic sample.
    107151 *
     
    121165    /** Our index among the parent's children. */
    122166    uint32_t                iSelf;
     167    /** Sub-tree filtering config (typically NULL). */
     168    VBoxGuiStatsFilterData *pFilter;
    123169    /** The unit string. (not allocated) */
    124170    const char             *pszUnit;
     171    /** The delta. */
     172    int64_t                 i64Delta;
     173    /** The name. */
     174    char                   *pszName;
     175    /** The length of the name. */
     176    size_t                  cchName;
     177    /** The description string. */
     178    QString                *pDescStr;
     179    /** The node state. */
     180    DBGGUISTATENODESTATE    enmState;
    125181    /** The data type.
    126182     * For filler nodes not containing data, this will be set to STAMTYPE_INVALID. */
     
    150206        QString            *pStr;
    151207    } Data;
    152     /** The delta. */
    153     int64_t                 i64Delta;
    154     /** The name. */
    155     char                   *pszName;
    156     /** The length of the name. */
    157     size_t                  cchName;
    158     /** The description string. */
    159     QString                *pDescStr;
    160     /** The node state. */
    161     DBGGUISTATENODESTATE    enmState;
    162208} DBGGUISTATSNODE;
    163209
     
    388434                                            const char *pszUnit, STAMVISIBILITY enmVisibility, const char *pszDesc, void *pvUser);
    389435
     436public:
    390437    /**
    391438     * Calculates the full path of a node.
     
    399446    static ssize_t getNodePath(PCDBGGUISTATSNODE pNode, char *psz, ssize_t cch);
    400447
     448protected:
    401449    /**
    402450     * Calculates the full path of a node, returning the string pointer.
     
    556604    /** Gets the value/times. */
    557605    static uint64_t getValueTimesAsUInt(PCDBGGUISTATSNODE pNode);
     606    /** Gets the value/avg. */
     607    static uint64_t getValueOrAvgAsUInt(PCDBGGUISTATSNODE pNode);
    558608    /** Gets the minimum value. */
    559609    static QString strMinValue(PCDBGGUISTATSNODE pNode);
     
    584634    static void destroyNode(PDBGGUISTATSNODE a_pNode);
    585635
     636public:
    586637    /**
    587638     * Converts an index to a node pointer.
     
    657708};
    658709
    659 
    660710#ifdef VBOXDBG_WITH_SORTED_AND_FILTERED_STATS
     711
    661712/**
    662713 * Model using the VM / STAM interface as data source.
     
    679730    void setShowUnusedRows(bool a_fHide);
    680731
     732    /**
     733     * Notification that a filter has been added, removed or modified.
     734     */
     735    void notifyFilterChanges();
     736
    681737protected:
    682738    /**
     
    701757    bool m_fShowUnusedRows;
    702758};
     759
     760
     761/**
     762 * Dialog for sub-tree filtering config.
     763 */
     764class VBoxDbgStatsFilterDialog : public QDialog
     765{
     766public:
     767    /**
     768     * Constructor.
     769     *
     770     * @param   a_pNode     The node to configure filtering for.
     771     */
     772    VBoxDbgStatsFilterDialog(QWidget *a_pParent, PCDBGGUISTATSNODE a_pNode);
     773
     774    /** Destructor. */
     775    virtual ~VBoxDbgStatsFilterDialog();
     776
     777    /**
     778     * Returns a copy of the filter data or NULL if all defaults.
     779     */
     780    VBoxGuiStatsFilterData *dupFilterData(void) const;
     781
     782protected slots:
     783
     784    /** Validates and (maybe) accepts the dialog data. */
     785    void validateAndAccept(void);
     786
     787protected:
     788    /**
     789     * Validates and converts the content of an uint64_t entry field.s
     790     *
     791     * @returns The converted value (or default)
     792     * @param   a_pField        The entry field widget.
     793     * @param   a_uDefault      The default return value.
     794     * @param   a_pszField      The field name (for error messages).
     795     * @param   a_pLstErrors    The error list to append validation errors to.
     796     */
     797    static uint64_t validateUInt64Field(QLineEdit const *a_pField, uint64_t a_uDefault,
     798                                        const char *a_pszField, QStringList *a_pLstErrors);
     799
     800
     801private:
     802    /** The filter data. */
     803    VBoxGuiStatsFilterData m_Data;
     804
     805    /** The minium value/average entry field. */
     806    QLineEdit *m_pValueAvgMin;
     807    /** The maxium value/average entry field. */
     808    QLineEdit *m_pValueAvgMax;
     809    /** The name filtering regexp entry field. */
     810    QLineEdit *m_pNameRegExp;
     811
     812    /** Regular expression for validating the uint64_t entry fields. */
     813    static QRegularExpression const s_UInt64ValidatorRegExp;
     814
     815    /**
     816     * Creates an entry field for a uint64_t value.
     817     */
     818    static QLineEdit *createUInt64LineEdit(uint64_t uValue);
     819};
     820
    703821#endif /* VBOXDBG_WITH_SORTED_AND_FILTERED_STATS */
     822
     823
     824/*********************************************************************************************************************************
     825*   Global Variables                                                                                                             *
     826*********************************************************************************************************************************/
     827/*static*/ uint32_t volatile VBoxGuiStatsFilterData::s_cInstances = 0;
    704828
    705829
     
    9391063    }
    9401064
     1065    VBoxGuiStatsFilterData const *pFilter = a_pNode->pFilter;
     1066    if (!pFilter)
     1067    { /* likely */ }
     1068    else
     1069    {
     1070        delete pFilter;
     1071        a_pNode->pFilter = NULL;
     1072    }
     1073
    9411074#ifdef VBOX_STRICT
    9421075    /* poison it. */
     
    9461079    a_pNode->papChildren++;
    9471080    a_pNode->cChildren = 8442;
     1081    a_pNode->pFilter++;
    9481082#endif
    9491083
     
    24862620
    24872621
     2622/*static*/ uint64_t
     2623VBoxDbgStatsModel::getValueOrAvgAsUInt(PCDBGGUISTATSNODE pNode)
     2624{
     2625    switch (pNode->enmType)
     2626    {
     2627        case STAMTYPE_COUNTER:
     2628            return pNode->Data.Counter.c;
     2629
     2630        case STAMTYPE_PROFILE:
     2631        case STAMTYPE_PROFILE_ADV:
     2632            if (pNode->Data.Profile.cPeriods)
     2633                return pNode->Data.Profile.cTicks / pNode->Data.Profile.cPeriods;
     2634            return 0;
     2635
     2636        case STAMTYPE_RATIO_U32:
     2637        case STAMTYPE_RATIO_U32_RESET:
     2638            return RT_MAKE_U64(pNode->Data.RatioU32.u32A, pNode->Data.RatioU32.u32B);
     2639
     2640        case STAMTYPE_CALLBACK:
     2641            return UINT64_MAX;
     2642
     2643        case STAMTYPE_U8:
     2644        case STAMTYPE_U8_RESET:
     2645        case STAMTYPE_X8:
     2646        case STAMTYPE_X8_RESET:
     2647            return pNode->Data.u8;
     2648
     2649        case STAMTYPE_U16:
     2650        case STAMTYPE_U16_RESET:
     2651        case STAMTYPE_X16:
     2652        case STAMTYPE_X16_RESET:
     2653            return pNode->Data.u16;
     2654
     2655        case STAMTYPE_U32:
     2656        case STAMTYPE_U32_RESET:
     2657        case STAMTYPE_X32:
     2658        case STAMTYPE_X32_RESET:
     2659            return pNode->Data.u32;
     2660
     2661        case STAMTYPE_U64:
     2662        case STAMTYPE_U64_RESET:
     2663        case STAMTYPE_X64:
     2664        case STAMTYPE_X64_RESET:
     2665            return pNode->Data.u64;
     2666
     2667        case STAMTYPE_BOOL:
     2668        case STAMTYPE_BOOL_RESET:
     2669            return pNode->Data.f;
     2670
     2671        default:
     2672            AssertMsgFailed(("%d\n", pNode->enmType));
     2673            RT_FALL_THRU();
     2674        case STAMTYPE_INVALID:
     2675            return UINT64_MAX;
     2676    }
     2677}
     2678
     2679
    24882680/*static*/ QString
    24892681VBoxDbgStatsModel::strMinValue(PCDBGGUISTATSNODE pNode)
     
    26762868        {
    26772869            case 0:
    2678                 return QString(pNode->pszName);
     2870                if (!pNode->pFilter)
     2871                    return QString(pNode->pszName);
     2872                return QString(pNode->pszName) + " (*)";
    26792873            case 1:
    26802874                return strUnit(pNode);
     
    30553249VBoxDbgStatsSortFileProxyModel::filterAcceptsRow(int a_iSrcRow, const QModelIndex &a_rSrcParent) const
    30563250{
    3057     if (!m_fShowUnusedRows)
    3058     {
    3059         PDBGGUISTATSNODE const pParent = nodeFromIndex(a_rSrcParent);
    3060         if (pParent)
     3251    /*
     3252     * Locate the node.
     3253     */
     3254    PDBGGUISTATSNODE pParent = nodeFromIndex(a_rSrcParent);
     3255    if (pParent)
     3256    {
     3257        if ((unsigned)a_iSrcRow < pParent->cChildren)
    30613258        {
    3062             if ((unsigned)a_iSrcRow < pParent->cChildren)
     3259            PDBGGUISTATSNODE const pNode = pParent->papChildren[a_iSrcRow];
     3260            if (pNode) /* paranoia */
    30633261            {
    3064                 PDBGGUISTATSNODE const pNode = pParent->papChildren[a_iSrcRow];
    3065                 if (pNode) /* paranoia */
     3262                /*
     3263                 * Apply the global unused-row filter.
     3264                 */
     3265                if (!m_fShowUnusedRows)
    30663266                {
    30673267                    /* Only relevant for leaf nodes. */
     
    31443344                        else
    31453345                            return false;
     3346                    }
     3347                }
     3348
     3349                /*
     3350                 * Look for additional filtering rules among the ancestors.
     3351                 */
     3352                if (VBoxGuiStatsFilterData::s_cInstances > 0 /* quick & dirty optimization */)
     3353                {
     3354                    VBoxGuiStatsFilterData const *pFilter = pParent->pFilter;
     3355                    while (!pFilter && (pParent = pParent->pParent) != NULL)
     3356                        pFilter = pParent->pFilter;
     3357                    if (pFilter)
     3358                    {
     3359                        if (pFilter->uMinValue > 0 || pFilter->uMaxValue != UINT64_MAX)
     3360                        {
     3361                            uint64_t const uValue = VBoxDbgStatsModel::getValueTimesAsUInt(pNode);
     3362                            if (   uValue < pFilter->uMinValue
     3363                                || uValue > pFilter->uMaxValue)
     3364                                return false;
     3365                        }
     3366                        if (pFilter->pRegexName)
     3367                        {
     3368                            if (!pFilter->pRegexName->match(pNode->pszName).hasMatch())
     3369                                return false;
     3370                        }
    31463371                    }
    31473372                }
     
    32123437
    32133438
     3439void
     3440VBoxDbgStatsSortFileProxyModel::notifyFilterChanges()
     3441{
     3442    invalidateRowsFilter();
     3443}
     3444
     3445
    32143446#endif /* VBOXDBG_WITH_SORTED_AND_FILTERED_STATS */
    32153447
     
    32653497     * Create and setup the actions.
    32663498     */
    3267     m_pExpandAct   = new QAction("Expand Tree", this);
    3268     m_pCollapseAct = new QAction("Collapse Tree", this);
    3269     m_pRefreshAct  = new QAction("&Refresh", this);
    3270     m_pResetAct    = new QAction("Rese&t", this);
    3271     m_pCopyAct     = new QAction("&Copy", this);
    3272     m_pToLogAct    = new QAction("To &Log", this);
    3273     m_pToRelLogAct = new QAction("T&o Release Log", this);
    3274     m_pAdjColumns  = new QAction("&Adjust Columns", this);
     3499    m_pExpandAct     = new QAction("Expand Tree", this);
     3500    m_pCollapseAct   = new QAction("Collapse Tree", this);
     3501    m_pRefreshAct    = new QAction("&Refresh", this);
     3502    m_pResetAct      = new QAction("Rese&t", this);
     3503    m_pCopyAct       = new QAction("&Copy", this);
     3504    m_pToLogAct      = new QAction("To &Log", this);
     3505    m_pToRelLogAct   = new QAction("T&o Release Log", this);
     3506    m_pAdjColumnsAct = new QAction("&Adjust Columns", this);
     3507#ifdef VBOXDBG_WITH_SORTED_AND_FILTERED_STATS
     3508    m_pFilterAct     = new QAction("&Filter...", this);
     3509#endif
    32753510
    32763511    m_pCopyAct->setShortcut(QKeySequence::Copy);
     
    32813516    m_pToLogAct->setShortcut(QKeySequence("Ctrl+Z"));
    32823517    m_pToRelLogAct->setShortcut(QKeySequence("Alt+Z"));
    3283     m_pAdjColumns->setShortcut(QKeySequence("Ctrl+A"));
     3518    m_pAdjColumnsAct->setShortcut(QKeySequence("Ctrl+A"));
     3519#ifdef VBOXDBG_WITH_SORTED_AND_FILTERED_STATS
     3520    //m_pFilterAct->setShortcut(QKeySequence("Ctrl+?"));
     3521#endif
    32843522
    32853523    addAction(m_pCopyAct);
     
    32903528    addAction(m_pToLogAct);
    32913529    addAction(m_pToRelLogAct);
    3292     addAction(m_pAdjColumns);
    3293 
    3294     connect(m_pExpandAct,   SIGNAL(triggered(bool)), this, SLOT(actExpand()));
    3295     connect(m_pCollapseAct, SIGNAL(triggered(bool)), this, SLOT(actCollapse()));
    3296     connect(m_pRefreshAct,  SIGNAL(triggered(bool)), this, SLOT(actRefresh()));
    3297     connect(m_pResetAct,    SIGNAL(triggered(bool)), this, SLOT(actReset()));
    3298     connect(m_pCopyAct,     SIGNAL(triggered(bool)), this, SLOT(actCopy()));
    3299     connect(m_pToLogAct,    SIGNAL(triggered(bool)), this, SLOT(actToLog()));
    3300     connect(m_pToRelLogAct, SIGNAL(triggered(bool)), this, SLOT(actToRelLog()));
    3301     connect(m_pAdjColumns,  SIGNAL(triggered(bool)), this, SLOT(actAdjColumns()));
     3530    addAction(m_pAdjColumnsAct);
     3531#ifdef VBOXDBG_WITH_SORTED_AND_FILTERED_STATS
     3532    addAction(m_pFilterAct);
     3533#endif
     3534
     3535    connect(m_pExpandAct,     SIGNAL(triggered(bool)), this, SLOT(actExpand()));
     3536    connect(m_pCollapseAct,   SIGNAL(triggered(bool)), this, SLOT(actCollapse()));
     3537    connect(m_pRefreshAct,    SIGNAL(triggered(bool)), this, SLOT(actRefresh()));
     3538    connect(m_pResetAct,      SIGNAL(triggered(bool)), this, SLOT(actReset()));
     3539    connect(m_pCopyAct,       SIGNAL(triggered(bool)), this, SLOT(actCopy()));
     3540    connect(m_pToLogAct,      SIGNAL(triggered(bool)), this, SLOT(actToLog()));
     3541    connect(m_pToRelLogAct,   SIGNAL(triggered(bool)), this, SLOT(actToRelLog()));
     3542    connect(m_pAdjColumnsAct, SIGNAL(triggered(bool)), this, SLOT(actAdjColumns()));
     3543#ifdef VBOXDBG_WITH_SORTED_AND_FILTERED_STATS
     3544    connect(m_pFilterAct,     SIGNAL(triggered(bool)), this, SLOT(actFilter()));
     3545#endif
    33023546
    33033547
     
    33233567    m_pBranchMenu->addAction(m_pExpandAct);
    33243568    m_pBranchMenu->addAction(m_pCollapseAct);
     3569#ifdef VBOXDBG_WITH_SORTED_AND_FILTERED_STATS
     3570    m_pBranchMenu->addSeparator();
     3571    m_pBranchMenu->addAction(m_pFilterAct);
     3572#endif
    33253573
    33263574    m_pViewMenu = new QMenu();
     
    33343582    m_pViewMenu->addAction(m_pCollapseAct);
    33353583    m_pViewMenu->addSeparator();
    3336     m_pViewMenu->addAction(m_pAdjColumns);
     3584    m_pViewMenu->addAction(m_pAdjColumnsAct);
     3585#ifdef VBOXDBG_WITH_SORTED_AND_FILTERED_STATS
     3586    m_pViewMenu->addAction(m_pFilterAct);
     3587#endif   
    33373588
    33383589    /* the header menu */
     
    33643615    DELETE_IT(m_pToLogAct);
    33653616    DELETE_IT(m_pToRelLogAct);
    3366     DELETE_IT(m_pAdjColumns);
     3617    DELETE_IT(m_pAdjColumnsAct);
     3618    DELETE_IT(m_pFilterAct);
    33673619#undef DELETE_IT
    33683620}
     
    36173869}
    36183870
     3871
     3872void
     3873VBoxDbgStatsView::actFilter()
     3874{
     3875#ifdef VBOXDBG_WITH_SORTED_AND_FILTERED_STATS
     3876    /*
     3877     * Get the node it applies to.
     3878     */
     3879    QModelIndex Idx = m_pCurMenu ? m_CurIndex : currentIndex();
     3880    if (Idx.isValid())
     3881        Idx == myGetRootIndex();
     3882    Idx = m_pProxyModel->mapToSource(Idx);
     3883    PDBGGUISTATSNODE pNode = m_pVBoxModel->nodeFromIndex(Idx);
     3884    if (pNode)
     3885    {
     3886        /*
     3887         * Display dialog (modal).
     3888         */
     3889        VBoxDbgStatsFilterDialog Dialog(this, pNode);
     3890        if (Dialog.exec() == QDialog::Accepted)
     3891        {
     3892            /** @todo it is possible that pNode is invalid now! */
     3893            VBoxGuiStatsFilterData * const pOldFilter = pNode->pFilter;
     3894            pNode->pFilter = Dialog.dupFilterData();
     3895            if (pOldFilter)
     3896                delete pOldFilter;
     3897            m_pProxyModel->notifyFilterChanges();
     3898        }
     3899    }
     3900#endif
     3901}
     3902
     3903
     3904
     3905
     3906
     3907
     3908/*
     3909 *
     3910 *      V B o x D b g S t a t s F i l t e r D i a l o g
     3911 *      V B o x D b g S t a t s F i l t e r D i a l o g
     3912 *      V B o x D b g S t a t s F i l t e r D i a l o g
     3913 *
     3914 *
     3915 */
     3916
     3917/* static */ QRegularExpression const VBoxDbgStatsFilterDialog::s_UInt64ValidatorRegExp("^([0-9]*|0[Xx][0-9a-fA-F]*)$");
     3918
     3919
     3920/*static*/ QLineEdit *
     3921VBoxDbgStatsFilterDialog::createUInt64LineEdit(uint64_t uValue)
     3922{
     3923    QLineEdit *pRet = new QLineEdit;
     3924    if (uValue == 0 || uValue == UINT64_MAX)
     3925        pRet->setText("");
     3926    else
     3927        pRet->setText(QString().number(uValue));
     3928    pRet->setValidator(new QRegularExpressionValidator(s_UInt64ValidatorRegExp));
     3929    return pRet;
     3930}
     3931
     3932
     3933VBoxDbgStatsFilterDialog::VBoxDbgStatsFilterDialog(QWidget *a_pParent, PCDBGGUISTATSNODE a_pNode)
     3934    : QDialog(a_pParent)
     3935{
     3936    /* Set the window title. */
     3937    static char s_szTitlePfx[] = "Filtering - ";
     3938    char szTitle[1024 + 128];
     3939    memcpy(szTitle, s_szTitlePfx, sizeof(s_szTitlePfx));
     3940    VBoxDbgStatsModel::getNodePath(a_pNode, &szTitle[sizeof(s_szTitlePfx) - 1], sizeof(szTitle) - sizeof(s_szTitlePfx));
     3941    setWindowTitle(szTitle);
     3942
     3943
     3944    /* Copy the old data if any. */
     3945    VBoxGuiStatsFilterData const * const pOldFilter = a_pNode->pFilter;
     3946    if (pOldFilter)
     3947    {
     3948        m_Data.uMinValue = pOldFilter->uMinValue;
     3949        m_Data.uMaxValue = pOldFilter->uMaxValue;
     3950        if (pOldFilter->pRegexName)
     3951            m_Data.pRegexName = new QRegularExpression(*pOldFilter->pRegexName);
     3952    }
     3953
     3954    /* Configure the dialog... */
     3955    QVBoxLayout *pMainLayout = new QVBoxLayout(this);
     3956
     3957    /* The value / average range: */
     3958    QGroupBox   *pValueAvgGrpBox = new QGroupBox("Value / Average");
     3959    QGridLayout *pValAvgLayout   = new QGridLayout;
     3960    QLabel      *pLabel          = new QLabel("Min");
     3961    m_pValueAvgMin = createUInt64LineEdit(m_Data.uMinValue);
     3962    pLabel->setBuddy(m_pValueAvgMin);
     3963    pValAvgLayout->addWidget(pLabel, 0, 0);
     3964    pValAvgLayout->addWidget(m_pValueAvgMin, 0, 1);
     3965
     3966    pLabel = new QLabel("Max");
     3967    m_pValueAvgMax = createUInt64LineEdit(m_Data.uMaxValue);
     3968    pLabel->setBuddy(m_pValueAvgMax);
     3969    pValAvgLayout->addWidget(pLabel, 1, 0);
     3970    pValAvgLayout->addWidget(m_pValueAvgMax, 1, 1);
     3971
     3972    pValueAvgGrpBox->setLayout(pValAvgLayout);
     3973    pMainLayout->addWidget(pValueAvgGrpBox);
     3974
     3975    /* The name filter. */
     3976    QGroupBox   *pNameGrpBox = new QGroupBox("Name RegExp");
     3977    QHBoxLayout *pNameLayout = new QHBoxLayout();
     3978    m_pNameRegExp = new QLineEdit;
     3979    if (m_Data.pRegexName)
     3980        m_pNameRegExp->setText(m_Data.pRegexName->pattern());
     3981    else
     3982        m_pNameRegExp->setText("");
     3983    m_pNameRegExp->setToolTip("Regular expression matching basenames (no parent) to show.");
     3984    pNameLayout->addWidget(m_pNameRegExp);
     3985    pNameGrpBox->setLayout(pNameLayout);
     3986    pMainLayout->addWidget(pNameGrpBox);
     3987
     3988    /* Buttons. */
     3989    QDialogButtonBox *pButtonBox = new QDialogButtonBox(QDialogButtonBox::Ok | QDialogButtonBox::Cancel, Qt::Horizontal, this);
     3990    pButtonBox->button(QDialogButtonBox::Ok)->setDefault(true);
     3991    connect(pButtonBox, &QDialogButtonBox::rejected, this, &VBoxDbgStatsFilterDialog::reject);
     3992    connect(pButtonBox, &QDialogButtonBox::accepted, this, &VBoxDbgStatsFilterDialog::validateAndAccept);
     3993    pMainLayout->addWidget(pButtonBox);
     3994}
     3995
     3996
     3997VBoxDbgStatsFilterDialog::~VBoxDbgStatsFilterDialog()
     3998{
     3999    /* anything? */
     4000}
     4001
     4002
     4003VBoxGuiStatsFilterData *
     4004VBoxDbgStatsFilterDialog::dupFilterData(void) const
     4005{
     4006    if (m_Data.isAllDefaults())
     4007        return NULL;
     4008    VBoxGuiStatsFilterData *pRet = new VBoxGuiStatsFilterData();
     4009    pRet->uMinValue  = m_Data.uMinValue;
     4010    pRet->uMaxValue  = m_Data.uMaxValue;
     4011    if (m_Data.pRegexName)
     4012        pRet->pRegexName = new QRegularExpression(*m_Data.pRegexName);
     4013    return pRet;
     4014}
     4015
     4016
     4017uint64_t
     4018VBoxDbgStatsFilterDialog::validateUInt64Field(QLineEdit const *a_pField, uint64_t a_uDefault,
     4019                                              const char *a_pszField, QStringList *a_pLstErrors)
     4020{
     4021    QString Str = a_pField->text().trimmed();
     4022    if (!Str.isEmpty())
     4023    {
     4024        QByteArray const   StrAsUtf8 = Str.toUtf8();
     4025        const char * const pszString = StrAsUtf8.constData();
     4026        uint64_t uValue = a_uDefault;
     4027        int vrc = RTStrToUInt64Full(pszString, 0, &uValue);
     4028        if (vrc == VINF_SUCCESS)
     4029            return uValue;
     4030        char szMsg[128];
     4031        RTStrPrintf(szMsg, sizeof(szMsg), "Invalid %s value: %Rrc - ", a_pszField, vrc);
     4032        a_pLstErrors->append(QString(szMsg) + Str);
     4033    }
     4034
     4035    return a_uDefault;
     4036}
     4037
     4038
     4039void
     4040VBoxDbgStatsFilterDialog::validateAndAccept()
     4041{
     4042    QStringList LstErrors;
     4043
     4044    /* The numeric fields. */
     4045    m_Data.uMinValue = validateUInt64Field(m_pValueAvgMin, 0,           "minimum value/avg", &LstErrors);
     4046    m_Data.uMaxValue = validateUInt64Field(m_pValueAvgMax, UINT64_MAX,  "maximum value/avg", &LstErrors);
     4047
     4048    /* The name regexp. */
     4049    QString Str = m_pNameRegExp->text().trimmed();
     4050    if (!Str.isEmpty())
     4051    {
     4052        if (!m_Data.pRegexName)
     4053            m_Data.pRegexName = new QRegularExpression();
     4054        m_Data.pRegexName->setPattern(Str);
     4055        if (!m_Data.pRegexName->isValid())
     4056            LstErrors.append("Invalid regular expression");
     4057    }
     4058    else if (m_Data.pRegexName)
     4059    {
     4060        delete m_Data.pRegexName;
     4061        m_Data.pRegexName = NULL;
     4062    }
     4063
     4064    /* Dismiss the dialog if everything is fine, otherwise complain and keep it open. */
     4065    if (LstErrors.isEmpty())
     4066        emit accept();
     4067    else
     4068    {
     4069        QMessageBox MsgBox(QMessageBox::Critical, "Invalid input", LstErrors.join("\n"), QMessageBox::Ok);
     4070        MsgBox.exec();
     4071    }
     4072}
    36194073
    36204074
     
    38184272#endif
    38194273}
     4274
  • trunk/src/VBox/Debugger/VBoxDbgStatsQt.h

    r103403 r103460  
    161161    void actToRelLog();
    162162    void actAdjColumns();
     163    void actFilter();
    163164    /** @} */
    164165
     
    204205    QAction *m_pToRelLogAct;
    205206    /** Adjust the columns. */
    206     QAction *m_pAdjColumns;
     207    QAction *m_pAdjColumnsAct;
     208    /** Filter sub-tree action. */
     209    QAction *m_pFilterAct;
    207210#if 0
    208211    /** Save Tree (to file) action. */
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette