forked from qt-creator/qt-creator
QmlProfiler: Improvements to searching timeline event notes
- Open timeline view when clicking search button - Use the usual search tool bar - Implement incremental search and the various search options Change-Id: Id83ab502cf4175738a825f531d9e454169663765 Reviewed-by: Ulf Hermann <ulf.hermann@theqtcompany.com>
This commit is contained in:
@@ -56,6 +56,7 @@
|
||||
|
||||
#include <coreplugin/coreconstants.h>
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
#include <coreplugin/find/findplugin.h>
|
||||
#include <coreplugin/icore.h>
|
||||
#include <coreplugin/messagemanager.h>
|
||||
#include <coreplugin/helpmanager.h>
|
||||
@@ -109,11 +110,8 @@ public:
|
||||
QTime m_recordingElapsedTime;
|
||||
QLabel *m_timeLabel;
|
||||
|
||||
// search field
|
||||
// open search
|
||||
QToolButton *m_searchButton;
|
||||
QLineEdit *m_searchField;
|
||||
QTimer *m_searchFieldTimer;
|
||||
int m_lastSearchResult;
|
||||
|
||||
// save and load actions
|
||||
QAction *m_saveQmlTrace;
|
||||
@@ -132,9 +130,6 @@ QmlProfilerTool::QmlProfilerTool(QObject *parent)
|
||||
d->m_clearButton = 0;
|
||||
d->m_timeLabel = 0;
|
||||
d->m_searchButton = 0;
|
||||
d->m_searchField = 0;
|
||||
d->m_searchFieldTimer = 0;
|
||||
d->m_lastSearchResult = -1;
|
||||
|
||||
d->m_profilerState = new QmlProfilerStateManager(this);
|
||||
connect(d->m_profilerState, SIGNAL(stateChanged()), this, SLOT(profilerStateChanged()));
|
||||
@@ -299,28 +294,10 @@ QWidget *QmlProfilerTool::createWidgets()
|
||||
|
||||
d->m_searchButton = new QToolButton;
|
||||
d->m_searchButton->setIcon(QIcon(QStringLiteral(":/timeline/ico_zoom.png")));
|
||||
d->m_searchButton->setToolTip(tr("Toggle the event search field."));
|
||||
d->m_searchButton->setCheckable(true);
|
||||
d->m_searchButton->setToolTip(tr("Search timeline event notes."));
|
||||
layout->addWidget(d->m_searchButton);
|
||||
|
||||
d->m_searchField = new QLineEdit;
|
||||
d->m_searchField->setToolTip(tr("Find events that have a specific note."));
|
||||
d->m_searchField->hide();
|
||||
layout->addWidget(d->m_searchField);
|
||||
|
||||
connect(d->m_searchButton, &QToolButton::toggled, [this] (bool checked) {
|
||||
d->m_searchField->setVisible(checked);
|
||||
if (checked) {
|
||||
d->m_searchButton->setText(d->m_searchButton->text() + QLatin1Char(':'));
|
||||
d->m_searchField->setFocus();
|
||||
d->m_searchField->selectAll();
|
||||
} else {
|
||||
QString str = d->m_searchButton->text();
|
||||
str.chop(1);
|
||||
d->m_searchButton->setText(str);
|
||||
}
|
||||
});
|
||||
connect(d->m_searchField, &QLineEdit::returnPressed, this, &QmlProfilerTool::findEvent);
|
||||
connect(d->m_searchButton, &QToolButton::clicked, this, &QmlProfilerTool::showTimeLineSearch);
|
||||
|
||||
layout->addStretch();
|
||||
toolbarWidget->setLayout(layout);
|
||||
@@ -437,43 +414,10 @@ void QmlProfilerTool::updateTimeDisplay()
|
||||
d->m_timeLabel->setText(tr("Elapsed: %1").arg(profilerTimeStr));
|
||||
}
|
||||
|
||||
void QmlProfilerTool::findEvent()
|
||||
void QmlProfilerTool::showTimeLineSearch()
|
||||
{
|
||||
const QString substr = d->m_searchField->text();
|
||||
QmlProfilerNotesModel *model = d->m_profilerModelManager->notesModel();
|
||||
|
||||
bool found = false;
|
||||
forever {
|
||||
for (int i = d->m_lastSearchResult + 1; i < model->count(); ++i) {
|
||||
if (model->text(i).contains(substr)) {
|
||||
d->m_lastSearchResult = i;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (found || d->m_lastSearchResult == -1)
|
||||
break;
|
||||
d->m_lastSearchResult = -1;
|
||||
}
|
||||
|
||||
if (found) {
|
||||
emit selectTimelineElement(model->timelineModel(d->m_lastSearchResult),
|
||||
model->timelineIndex(d->m_lastSearchResult));
|
||||
d->m_searchField->setFocus();
|
||||
} else {
|
||||
QPalette p = d->m_searchField->palette();
|
||||
p.setColor(QPalette::Text, Qt::red);
|
||||
d->m_searchField->setPalette(p);
|
||||
if (!d->m_searchFieldTimer) {
|
||||
d->m_searchFieldTimer = new QTimer(this);
|
||||
connect(d->m_searchFieldTimer, &QTimer::timeout, [this] () {
|
||||
d->m_searchField->setPalette(d->m_searchField->parentWidget()->palette());
|
||||
});
|
||||
}
|
||||
if (d->m_searchFieldTimer->isActive())
|
||||
d->m_searchFieldTimer->stop();
|
||||
d->m_searchFieldTimer->start(1500);
|
||||
}
|
||||
d->m_viewContainer->raiseTimeline();
|
||||
Core::FindPlugin::instance()->openFindToolBar(Core::FindPlugin::FindForwardDirection);
|
||||
}
|
||||
|
||||
void QmlProfilerTool::clearData()
|
||||
|
||||
@@ -70,9 +70,6 @@ public:
|
||||
static void logError(const QString &msg);
|
||||
static void showNonmodalWarning(const QString &warningMsg);
|
||||
|
||||
signals:
|
||||
void selectTimelineElement(int modelId, int eventIndex);
|
||||
|
||||
public slots:
|
||||
void profilerStateChanged();
|
||||
void clientRecordingChanged();
|
||||
@@ -90,7 +87,7 @@ private slots:
|
||||
void showErrorDialog(const QString &error);
|
||||
void profilerDataModelStateChanged();
|
||||
void updateTimeDisplay();
|
||||
void findEvent();
|
||||
void showTimeLineSearch();
|
||||
|
||||
void showSaveOption();
|
||||
void showLoadOption();
|
||||
|
||||
@@ -45,9 +45,10 @@
|
||||
#include "timeline/timelinerenderer.h"
|
||||
#include "timeline/timelineoverviewrenderer.h"
|
||||
|
||||
#include <aggregation/aggregate.h>
|
||||
// Needed for the load&save actions in the context menu
|
||||
#include <analyzerbase/ianalyzertool.h>
|
||||
|
||||
#include <coreplugin/findplaceholder.h>
|
||||
#include <utils/styledbar.h>
|
||||
|
||||
#include <QQmlContext>
|
||||
@@ -61,6 +62,7 @@
|
||||
#include <QQuickItem>
|
||||
#include <QQuickWidget>
|
||||
#include <QApplication>
|
||||
#include <QTextCursor>
|
||||
|
||||
#include <math.h>
|
||||
|
||||
@@ -112,8 +114,14 @@ QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, QmlProfilerTool *pro
|
||||
d->m_mainView = new QQuickWidget(this);
|
||||
d->m_mainView->setResizeMode(QQuickWidget::SizeRootObjectToView);
|
||||
d->m_mainView->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
|
||||
setFocusProxy(d->m_mainView);
|
||||
|
||||
Aggregation::Aggregate *agg = new Aggregation::Aggregate;
|
||||
agg->add(d->m_mainView);
|
||||
agg->add(new TraceViewFindSupport(this, modelManager));
|
||||
|
||||
groupLayout->addWidget(d->m_mainView);
|
||||
groupLayout->addWidget(new Core::FindToolBarPlaceHolder(this));
|
||||
setLayout(groupLayout);
|
||||
|
||||
d->m_profilerTool = profilerTool;
|
||||
@@ -122,8 +130,6 @@ QmlProfilerTraceView::QmlProfilerTraceView(QWidget *parent, QmlProfilerTool *pro
|
||||
d->m_modelProxy = new Timeline::TimelineModelAggregator(modelManager->notesModel(), this);
|
||||
d->m_modelManager = modelManager;
|
||||
|
||||
connect(qobject_cast<QmlProfilerTool *>(profilerTool), &QmlProfilerTool::selectTimelineElement,
|
||||
this, &QmlProfilerTraceView::selectByEventIndex);
|
||||
connect(modelManager,SIGNAL(dataAvailable()), d->m_modelProxy,SIGNAL(dataAvailable()));
|
||||
|
||||
// external models pushed on top
|
||||
@@ -307,5 +313,122 @@ void QmlProfilerTraceView::changeEvent(QEvent *e)
|
||||
}
|
||||
}
|
||||
|
||||
TraceViewFindSupport::TraceViewFindSupport(QmlProfilerTraceView *view,
|
||||
QmlProfilerModelManager *manager)
|
||||
: m_view(view), m_modelManager(manager)
|
||||
{
|
||||
}
|
||||
|
||||
bool TraceViewFindSupport::supportsReplace() const
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
Core::FindFlags TraceViewFindSupport::supportedFindFlags() const
|
||||
{
|
||||
return Core::FindBackward | Core::FindCaseSensitively | Core::FindRegularExpression
|
||||
| Core::FindWholeWords;
|
||||
}
|
||||
|
||||
void TraceViewFindSupport::resetIncrementalSearch()
|
||||
{
|
||||
m_incrementalStartPos = -1;
|
||||
m_incrementalWrappedState = false;
|
||||
}
|
||||
|
||||
void TraceViewFindSupport::clearHighlights()
|
||||
{
|
||||
}
|
||||
|
||||
QString TraceViewFindSupport::currentFindString() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
QString TraceViewFindSupport::completedFindString() const
|
||||
{
|
||||
return QString();
|
||||
}
|
||||
|
||||
Core::IFindSupport::Result TraceViewFindSupport::findIncremental(const QString &txt,
|
||||
Core::FindFlags findFlags)
|
||||
{
|
||||
if (m_incrementalStartPos < 0)
|
||||
m_incrementalStartPos = qMax(m_currentPosition, 0);
|
||||
bool wrapped = false;
|
||||
bool found = find(txt, findFlags, m_incrementalStartPos, &wrapped);
|
||||
if (wrapped != m_incrementalWrappedState && found) {
|
||||
m_incrementalWrappedState = wrapped;
|
||||
showWrapIndicator(m_view);
|
||||
}
|
||||
return found ? Core::IFindSupport::Found : Core::IFindSupport::NotFound;
|
||||
}
|
||||
|
||||
Core::IFindSupport::Result TraceViewFindSupport::findStep(const QString &txt,
|
||||
Core::FindFlags findFlags)
|
||||
{
|
||||
int start = (findFlags & Core::FindBackward) ? m_currentPosition : m_currentPosition + 1;
|
||||
bool wrapped;
|
||||
bool found = find(txt, findFlags, start, &wrapped);
|
||||
if (wrapped)
|
||||
showWrapIndicator(m_view);
|
||||
if (found) {
|
||||
m_incrementalStartPos = m_currentPosition;
|
||||
m_incrementalWrappedState = false;
|
||||
}
|
||||
return found ? Core::IFindSupport::Found : Core::IFindSupport::NotFound;
|
||||
}
|
||||
|
||||
// "start" is the model index that is searched first in a forward search, i.e. as if the
|
||||
// "cursor" were between start-1 and start
|
||||
bool TraceViewFindSupport::find(const QString &txt, Core::FindFlags findFlags, int start,
|
||||
bool *wrapped)
|
||||
{
|
||||
if (wrapped)
|
||||
*wrapped = false;
|
||||
if (!findOne(txt, findFlags, start)) {
|
||||
int secondStart;
|
||||
if (findFlags & Core::FindBackward)
|
||||
secondStart = m_modelManager->notesModel()->count();
|
||||
else
|
||||
secondStart = 0;
|
||||
if (!findOne(txt, findFlags, secondStart))
|
||||
return false;
|
||||
if (wrapped)
|
||||
*wrapped = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// "start" is the model index that is searched first in a forward search, i.e. as if the
|
||||
// "cursor" were between start-1 and start
|
||||
bool TraceViewFindSupport::findOne(const QString &txt, Core::FindFlags findFlags, int start)
|
||||
{
|
||||
bool caseSensitiveSearch = (findFlags & Core::FindCaseSensitively);
|
||||
QRegExp regexp(txt);
|
||||
regexp.setPatternSyntax((findFlags & Core::FindRegularExpression) ? QRegExp::RegExp : QRegExp::FixedString);
|
||||
regexp.setCaseSensitivity(caseSensitiveSearch ? Qt::CaseSensitive : Qt::CaseInsensitive);
|
||||
QTextDocument::FindFlags flags;
|
||||
if (caseSensitiveSearch)
|
||||
flags |= QTextDocument::FindCaseSensitively;
|
||||
if (findFlags & Core::FindWholeWords)
|
||||
flags |= QTextDocument::FindWholeWords;
|
||||
bool forwardSearch = !(findFlags & Core::FindBackward);
|
||||
int increment = forwardSearch ? +1 : -1;
|
||||
int current = forwardSearch ? start : start - 1;
|
||||
QmlProfilerNotesModel *model = m_modelManager->notesModel();
|
||||
while (current >= 0 && current < model->count()) {
|
||||
QTextDocument doc(model->text(current)); // for automatic handling of WholeWords option
|
||||
if (!doc.find(regexp, 0, flags).isNull()) {
|
||||
m_currentPosition = current;
|
||||
m_view->selectByEventIndex(model->timelineModel(m_currentPosition),
|
||||
model->timelineIndex(m_currentPosition));
|
||||
return true;
|
||||
}
|
||||
current += increment;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
@@ -32,8 +32,11 @@
|
||||
#define QMLPROFILERTRACEVIEW_H
|
||||
|
||||
#include "qmlprofilermodelmanager.h"
|
||||
#include <QWidget>
|
||||
|
||||
#include <coreplugin/find/ifindsupport.h>
|
||||
|
||||
#include <QTimer>
|
||||
#include <QWidget>
|
||||
|
||||
namespace QmlProfiler {
|
||||
|
||||
@@ -83,6 +86,33 @@ private:
|
||||
QmlProfilerTraceViewPrivate *d;
|
||||
};
|
||||
|
||||
class TraceViewFindSupport : public Core::IFindSupport
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
TraceViewFindSupport(QmlProfilerTraceView *view, QmlProfilerModelManager *manager);
|
||||
|
||||
bool supportsReplace() const override;
|
||||
Core::FindFlags supportedFindFlags() const override;
|
||||
void resetIncrementalSearch() override;
|
||||
void clearHighlights() override;
|
||||
QString currentFindString() const override;
|
||||
QString completedFindString() const override;
|
||||
Result findIncremental(const QString &txt, Core::FindFlags findFlags) override;
|
||||
Result findStep(const QString &txt, Core::FindFlags findFlags) override;
|
||||
|
||||
private:
|
||||
bool find(const QString &txt, Core::FindFlags findFlags, int start, bool *wrapped);
|
||||
bool findOne(const QString &txt, Core::FindFlags findFlags, int start);
|
||||
|
||||
QmlProfilerTraceView *m_view;
|
||||
QmlProfilerModelManager *m_modelManager;
|
||||
int m_incrementalStartPos = -1;
|
||||
bool m_incrementalWrappedState = false;
|
||||
int m_currentPosition = -1;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace QmlProfiler
|
||||
|
||||
|
||||
@@ -53,6 +53,7 @@ class QmlProfilerViewManager::QmlProfilerViewManagerPrivate {
|
||||
public:
|
||||
QmlProfilerViewManagerPrivate(QmlProfilerViewManager *qq) { Q_UNUSED(qq); }
|
||||
|
||||
QDockWidget *timelineDock;
|
||||
QmlProfilerTraceView *traceView;
|
||||
QmlProfilerEventsWidget *eventsView;
|
||||
QV8ProfilerEventsWidget *v8profilerView;
|
||||
@@ -124,19 +125,19 @@ void QmlProfilerViewManager::createViews()
|
||||
|
||||
QDockWidget *eventsDock = AnalyzerManager::createDockWidget
|
||||
(QmlProfilerToolId, d->eventsView);
|
||||
QDockWidget *timelineDock = AnalyzerManager::createDockWidget
|
||||
d->timelineDock = AnalyzerManager::createDockWidget
|
||||
(QmlProfilerToolId, d->traceView);
|
||||
QDockWidget *v8profilerDock = AnalyzerManager::createDockWidget
|
||||
(QmlProfilerToolId, d->v8profilerView);
|
||||
|
||||
eventsDock->show();
|
||||
timelineDock->show();
|
||||
d->timelineDock->show();
|
||||
v8profilerDock->show();
|
||||
|
||||
mw->splitDockWidget(mw->toolBarDockWidget(), timelineDock, Qt::Vertical);
|
||||
mw->tabifyDockWidget(timelineDock, eventsDock);
|
||||
mw->splitDockWidget(mw->toolBarDockWidget(), d->timelineDock, Qt::Vertical);
|
||||
mw->tabifyDockWidget(d->timelineDock, eventsDock);
|
||||
mw->tabifyDockWidget(eventsDock, v8profilerDock);
|
||||
timelineDock->raise();
|
||||
d->timelineDock->raise();
|
||||
|
||||
new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->eventsView);
|
||||
new QmlProfilerStateWidget(d->profilerState, d->profilerModelManager, d->traceView);
|
||||
@@ -168,6 +169,12 @@ void QmlProfilerViewManager::getStatisticsInRange(qint64 rangeStart, qint64 rang
|
||||
d->eventsView->getStatisticsInRange(rangeStart, rangeEnd);
|
||||
}
|
||||
|
||||
void QmlProfilerViewManager::raiseTimeline()
|
||||
{
|
||||
d->timelineDock->raise();
|
||||
d->traceView->setFocus();
|
||||
}
|
||||
|
||||
void QmlProfilerViewManager::clear()
|
||||
{
|
||||
d->traceView->clear();
|
||||
|
||||
@@ -60,6 +60,8 @@ public:
|
||||
bool hasGlobalStats() const;
|
||||
void getStatisticsInRange(qint64 rangeStart, qint64 rangeEnd);
|
||||
|
||||
void raiseTimeline();
|
||||
|
||||
public slots:
|
||||
void clear();
|
||||
|
||||
|
||||
Reference in New Issue
Block a user