Commit af2db925 authored by Eike Ziller's avatar Eike Ziller
Browse files

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: default avatarUlf Hermann <ulf.hermann@theqtcompany.com>
parent 445cf258
......@@ -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();
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment