QmlProfiler: Apply d-pointer pattern to TimelineRenderer

TimelineRenderer will be a public class in the timeline library. We
don't want to expose its private members.

Change-Id: Ib82ab8b30f702293d1d8b5d101b7dd0e3380194c
Reviewed-by: Kai Koehne <kai.koehne@theqtcompany.com>
This commit is contained in:
Ulf Hermann
2014-12-09 11:55:08 +01:00
parent 516c0d6020
commit f87622c363
5 changed files with 314 additions and 203 deletions

View File

@@ -86,7 +86,8 @@ HEADERS += \
timelinerenderpass.h \ timelinerenderpass.h \
timelinerenderstate.h \ timelinerenderstate.h \
timelinenotesmodel.h \ timelinenotesmodel.h \
timelinenotesmodel_p.h timelinenotesmodel_p.h \
timelinerenderer_p.h
RESOURCES += \ RESOURCES += \
qml/qmlprofiler.qrc qml/qmlprofiler.qrc

View File

@@ -55,7 +55,7 @@ QtcPlugin {
"timelinemodelaggregator.cpp", "timelinemodelaggregator.h", "timelinemodelaggregator.cpp", "timelinemodelaggregator.h",
"timelinenotesmodel.cpp", "timelinenotesmodel.h", "timelinenotesmodel_p.h", "timelinenotesmodel.cpp", "timelinenotesmodel.h", "timelinenotesmodel_p.h",
"timelinenotesrenderpass.cpp", "timelinenotesrenderpass.h", "timelinenotesrenderpass.cpp", "timelinenotesrenderpass.h",
"timelinerenderer.cpp", "timelinerenderer.h", "timelinerenderer.cpp", "timelinerenderer.h", "timelinerenderer_p.h",
"timelinerenderpass.cpp", "timelinerenderpass.h", "timelinerenderpass.cpp", "timelinerenderpass.h",
"timelinerenderstate.cpp", "timelinerenderstate.h", "timelinerenderstate.cpp", "timelinerenderstate.h",
"timelineselectionrenderpass.cpp", "timelineselectionrenderpass.h", "timelineselectionrenderpass.cpp", "timelineselectionrenderpass.h",

View File

@@ -28,7 +28,7 @@
** **
****************************************************************************/ ****************************************************************************/
#include "timelinerenderer.h" #include "timelinerenderer_p.h"
#include "timelinerenderpass.h" #include "timelinerenderpass.h"
#include "qmlprofilernotesmodel.h" #include "qmlprofilernotesmodel.h"
#include "timelineitemsrenderpass.h" #include "timelineitemsrenderpass.h"
@@ -50,113 +50,159 @@
namespace Timeline { namespace Timeline {
TimelineRenderer::TimelineRendererPrivate::TimelineRendererPrivate(TimelineRenderer *q) :
model(0), zoomer(0), notes(0), selectedItem(-1), selectionLocked(true), modelDirty(false),
rowHeightsDirty(false), rowCountsDirty(false), lastState(0), q_ptr(q)
{
resetCurrentSelection();
}
TimelineRenderer::TimelineRenderer(QQuickItem *parent) : TimelineRenderer::TimelineRenderer(QQuickItem *parent) :
QQuickItem(parent), m_model(0), m_zoomer(0), m_notes(0), QQuickItem(parent), d_ptr(new TimelineRendererPrivate(this))
m_selectedItem(-1), m_selectionLocked(true), m_modelDirty(false),
m_rowHeightsDirty(false), m_rowCountsDirty(false), m_lastState(0)
{ {
setFlag(QQuickItem::ItemHasContents); setFlag(QQuickItem::ItemHasContents);
resetCurrentSelection();
setAcceptedMouseButtons(Qt::LeftButton); setAcceptedMouseButtons(Qt::LeftButton);
setAcceptHoverEvents(true); setAcceptHoverEvents(true);
} }
bool TimelineRenderer::selectionLocked() const
{
Q_D(const TimelineRenderer);
return d->selectionLocked;
}
int TimelineRenderer::selectedItem() const
{
Q_D(const TimelineRenderer);
return d->selectedItem;
}
TimelineModel *TimelineRenderer::model() const
{
Q_D(const TimelineRenderer);
return d->model;
}
void TimelineRenderer::setModel(TimelineModel *model) void TimelineRenderer::setModel(TimelineModel *model)
{ {
if (m_model == model) Q_D(TimelineRenderer);
if (d->model == model)
return; return;
if (m_model) { if (d->model) {
disconnect(m_model, SIGNAL(expandedChanged()), this, SLOT(update())); disconnect(d->model, SIGNAL(expandedChanged()), this, SLOT(update()));
disconnect(m_model, SIGNAL(hiddenChanged()), this, SLOT(update())); disconnect(d->model, SIGNAL(hiddenChanged()), this, SLOT(update()));
disconnect(m_model, SIGNAL(expandedRowHeightChanged(int,int)), disconnect(d->model, SIGNAL(expandedRowHeightChanged(int,int)),
this, SLOT(setRowHeightsDirty())); this, SLOT(setRowHeightsDirty()));
disconnect(m_model, SIGNAL(emptyChanged()), this, SLOT(setModelDirty())); disconnect(d->model, SIGNAL(emptyChanged()), this, SLOT(setModelDirty()));
disconnect(m_model, SIGNAL(expandedRowCountChanged()), this, SLOT(setRowCountsDirty())); disconnect(d->model, SIGNAL(expandedRowCountChanged()), this, SLOT(setRowCountsDirty()));
disconnect(m_model, SIGNAL(collapsedRowCountChanged()), this, SLOT(setRowCountsDirty())); disconnect(d->model, SIGNAL(collapsedRowCountChanged()), this, SLOT(setRowCountsDirty()));
} }
m_model = model; d->model = model;
if (m_model) { if (d->model) {
connect(m_model, SIGNAL(expandedChanged()), this, SLOT(update())); connect(d->model, SIGNAL(expandedChanged()), this, SLOT(update()));
connect(m_model, SIGNAL(hiddenChanged()), this, SLOT(update())); connect(d->model, SIGNAL(hiddenChanged()), this, SLOT(update()));
connect(m_model, SIGNAL(expandedRowHeightChanged(int,int)), connect(d->model, SIGNAL(expandedRowHeightChanged(int,int)),
this, SLOT(setRowHeightsDirty())); this, SLOT(setRowHeightsDirty()));
connect(m_model, SIGNAL(emptyChanged()), this, SLOT(setModelDirty())); connect(d->model, SIGNAL(emptyChanged()), this, SLOT(setModelDirty()));
connect(m_model, SIGNAL(expandedRowCountChanged()), this, SLOT(setRowCountsDirty())); connect(d->model, SIGNAL(expandedRowCountChanged()), this, SLOT(setRowCountsDirty()));
connect(m_model, SIGNAL(collapsedRowCountChanged()), this, SLOT(setRowCountsDirty())); connect(d->model, SIGNAL(collapsedRowCountChanged()), this, SLOT(setRowCountsDirty()));
m_renderPasses = model->supportedRenderPasses(); d->renderPasses = d->model->supportedRenderPasses();
} }
setModelDirty(); setModelDirty();
setRowHeightsDirty(); setRowHeightsDirty();
setRowCountsDirty(); setRowCountsDirty();
emit modelChanged(m_model); emit modelChanged(d->model);
}
TimelineZoomControl *TimelineRenderer::zoomer() const
{
Q_D(const TimelineRenderer);
return d->zoomer;
} }
void TimelineRenderer::setZoomer(TimelineZoomControl *zoomer) void TimelineRenderer::setZoomer(TimelineZoomControl *zoomer)
{ {
if (zoomer != m_zoomer) { Q_D(TimelineRenderer);
if (m_zoomer != 0) if (zoomer != d->zoomer) {
disconnect(m_zoomer, SIGNAL(windowChanged(qint64,qint64)), this, SLOT(update())); if (d->zoomer != 0)
m_zoomer = zoomer; disconnect(d->zoomer, SIGNAL(windowChanged(qint64,qint64)), this, SLOT(update()));
if (m_zoomer != 0) d->zoomer = zoomer;
connect(m_zoomer, SIGNAL(windowChanged(qint64,qint64)), this, SLOT(update())); if (d->zoomer != 0)
connect(d->zoomer, SIGNAL(windowChanged(qint64,qint64)), this, SLOT(update()));
emit zoomerChanged(zoomer); emit zoomerChanged(zoomer);
update(); update();
} }
} }
TimelineNotesModel *TimelineRenderer::notes() const
{
Q_D(const TimelineRenderer);
return d->notes;
}
void TimelineRenderer::setNotes(TimelineNotesModel *notes) void TimelineRenderer::setNotes(TimelineNotesModel *notes)
{ {
if (m_notes == notes) Q_D(TimelineRenderer);
if (d->notes == notes)
return; return;
if (m_notes) if (d->notes)
disconnect(m_notes, &TimelineNotesModel::changed, disconnect(d->notes, &TimelineNotesModel::changed,
this, &TimelineRenderer::setNotesDirty); this, &TimelineRenderer::setNotesDirty);
m_notes = notes; d->notes = notes;
if (m_notes) if (d->notes)
connect(m_notes, &TimelineNotesModel::changed, connect(d->notes, &TimelineNotesModel::changed,
this, &TimelineRenderer::setNotesDirty); this, &TimelineRenderer::setNotesDirty);
emit notesChanged(m_notes); emit notesChanged(d->notes);
update(); update();
} }
bool TimelineRenderer::modelDirty() const bool TimelineRenderer::modelDirty() const
{ {
return m_modelDirty; Q_D(const TimelineRenderer);
return d->modelDirty;
} }
bool TimelineRenderer::notesDirty() const bool TimelineRenderer::notesDirty() const
{ {
return m_notesDirty; Q_D(const TimelineRenderer);
return d->notesDirty;
} }
bool TimelineRenderer::rowHeightsDirty() const bool TimelineRenderer::rowHeightsDirty() const
{ {
return m_rowHeightsDirty; Q_D(const TimelineRenderer);
return d->rowHeightsDirty;
} }
void TimelineRenderer::resetCurrentSelection() bool TimelineRenderer::rowCountsDirty() const
{ {
m_currentSelection.startTime = -1; Q_D(const TimelineRenderer);
m_currentSelection.endTime = -1; return d->rowCountsDirty;
m_currentSelection.row = -1;
m_currentSelection.eventIndex = -1;
} }
TimelineRenderState *TimelineRenderer::findRenderState() void TimelineRenderer::TimelineRendererPrivate::resetCurrentSelection()
{
currentSelection.startTime = -1;
currentSelection.endTime = -1;
currentSelection.row = -1;
currentSelection.eventIndex = -1;
}
TimelineRenderState *TimelineRenderer::TimelineRendererPrivate::findRenderState()
{ {
int newLevel = 0; int newLevel = 0;
int newOffset = 0; int newOffset = 0;
int level; int level;
int offset; int offset;
qint64 newStart = m_zoomer->traceStart(); qint64 newStart = zoomer->traceStart();
qint64 newEnd = m_zoomer->traceEnd(); qint64 newEnd = zoomer->traceEnd();
qint64 start; qint64 start;
qint64 end; qint64 end;
do { do {
@@ -166,60 +212,61 @@ TimelineRenderState *TimelineRenderer::findRenderState()
end = newEnd; end = newEnd;
newLevel = level + 1; newLevel = level + 1;
qint64 range = m_zoomer->traceDuration() >> newLevel; qint64 range = zoomer->traceDuration() >> newLevel;
newOffset = (m_zoomer->windowStart() - m_zoomer->traceStart() + range / 2) / range; newOffset = (zoomer->windowStart() - zoomer->traceStart() + range / 2) / range;
newStart = m_zoomer->traceStart() + newOffset * range - range / 2; newStart = zoomer->traceStart() + newOffset * range - range / 2;
newEnd = newStart + range; newEnd = newStart + range;
} while (newStart < m_zoomer->windowStart() && newEnd > m_zoomer->windowEnd()); } while (newStart < zoomer->windowStart() && newEnd > zoomer->windowEnd());
if (m_renderStates.length() <= level) if (renderStates.length() <= level)
m_renderStates.resize(level + 1); renderStates.resize(level + 1);
if (m_renderStates[level].length() <= offset) if (renderStates[level].length() <= offset)
m_renderStates[level].resize(offset + 1); renderStates[level].resize(offset + 1);
TimelineRenderState *state = m_renderStates[level][offset]; TimelineRenderState *state = renderStates[level][offset];
if (state == 0) { if (state == 0) {
state = new TimelineRenderState(start, end, 1.0 / static_cast<qreal>(SafeFloatMax), state = new TimelineRenderState(start, end, 1.0 / static_cast<qreal>(SafeFloatMax),
m_renderPasses.size()); renderPasses.size());
m_renderStates[level][offset] = state; renderStates[level][offset] = state;
} }
return state; return state;
} }
QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node, QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node, UpdatePaintNodeData *updatePaintNodeData)
UpdatePaintNodeData *updatePaintNodeData)
{ {
Q_D(TimelineRenderer);
Q_UNUSED(updatePaintNodeData) Q_UNUSED(updatePaintNodeData)
if (!m_model || m_model->hidden() || m_model->isEmpty() || m_zoomer->windowDuration() <= 0) { if (!d->model || d->model->hidden() || d->model->isEmpty() ||
d->zoomer->windowDuration() <= 0) {
delete node; delete node;
return 0; return 0;
} else if (node == 0) { } else if (node == 0) {
node = new QSGTransformNode; node = new QSGTransformNode;
} }
qreal spacing = width() / m_zoomer->windowDuration(); qreal spacing = width() / d->zoomer->windowDuration();
if (m_modelDirty || m_rowCountsDirty) { if (d->modelDirty || d->rowCountsDirty) {
node->removeAllChildNodes(); node->removeAllChildNodes();
foreach (QVector<TimelineRenderState *> stateVector, m_renderStates) foreach (QVector<TimelineRenderState *> stateVector, d->renderStates)
qDeleteAll(stateVector); qDeleteAll(stateVector);
m_renderStates.clear(); d->renderStates.clear();
m_lastState = 0; d->lastState = 0;
} }
TimelineRenderState *state = findRenderState(); TimelineRenderState *state = d->findRenderState();
int lastIndex = m_model->lastIndex(m_zoomer->windowEnd()); int lastIndex = d->model->lastIndex(d->zoomer->windowEnd());
int firstIndex = m_model->firstIndex(m_zoomer->windowStart()); int firstIndex = d->model->firstIndex(d->zoomer->windowStart());
for (int i = 0; i < m_renderPasses.length(); ++i) for (int i = 0; i < d->renderPasses.length(); ++i)
state->setPassState(i, m_renderPasses[i]->update(this, state, state->passState(i), state->setPassState(i, d->renderPasses[i]->update(this, state, state->passState(i),
firstIndex, lastIndex + 1, firstIndex, lastIndex + 1,
state != m_lastState, spacing)); state != d->lastState, spacing));
if (state->isEmpty()) { // new state if (state->isEmpty()) { // new state
for (int pass = 0; pass < m_renderPasses.length(); ++pass) { for (int pass = 0; pass < d->renderPasses.length(); ++pass) {
const TimelineRenderPass::State *passState = state->passState(pass); const TimelineRenderPass::State *passState = state->passState(pass);
if (!passState) if (!passState)
continue; continue;
@@ -230,9 +277,9 @@ QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node,
} }
int row = 0; int row = 0;
for (int i = 0; i < m_model->expandedRowCount(); ++i) { for (int i = 0; i < d->model->expandedRowCount(); ++i) {
QSGTransformNode *rowNode = new QSGTransformNode; QSGTransformNode *rowNode = new QSGTransformNode;
for (int pass = 0; pass < m_renderPasses.length(); ++pass) { for (int pass = 0; pass < d->renderPasses.length(); ++pass) {
const TimelineRenderPass::State *passState = state->passState(pass); const TimelineRenderPass::State *passState = state->passState(pass);
if (passState && passState->expandedRows.length() > row) { if (passState && passState->expandedRows.length() > row) {
QSGNode *rowChildNode = passState->expandedRows[row]; QSGNode *rowChildNode = passState->expandedRows[row];
@@ -244,12 +291,12 @@ QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node,
++row; ++row;
} }
for (int row = 0; row < m_model->collapsedRowCount(); ++row) { for (int row = 0; row < d->model->collapsedRowCount(); ++row) {
QSGTransformNode *rowNode = new QSGTransformNode; QSGTransformNode *rowNode = new QSGTransformNode;
QMatrix4x4 matrix; QMatrix4x4 matrix;
matrix.translate(0, row * TimelineModel::defaultRowHeight(), 0); matrix.translate(0, row * TimelineModel::defaultRowHeight(), 0);
rowNode->setMatrix(matrix); rowNode->setMatrix(matrix);
for (int pass = 0; pass < m_renderPasses.length(); ++pass) { for (int pass = 0; pass < d->renderPasses.length(); ++pass) {
const TimelineRenderPass::State *passState = state->passState(pass); const TimelineRenderPass::State *passState = state->passState(pass);
if (passState && passState->collapsedRows.length() > row) { if (passState && passState->collapsedRows.length() > row) {
QSGNode *rowChildNode = passState->collapsedRows[row]; QSGNode *rowChildNode = passState->collapsedRows[row];
@@ -261,12 +308,12 @@ QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node,
} }
} }
if (m_rowHeightsDirty || state != m_lastState) { if (d->rowHeightsDirty || state != d->lastState) {
int row = 0; int row = 0;
qreal offset = 0; qreal offset = 0;
for (QSGNode *rowNode = state->expandedRowRoot()->firstChild(); rowNode != 0; for (QSGNode *rowNode = state->expandedRowRoot()->firstChild(); rowNode != 0;
rowNode = rowNode->nextSibling()) { rowNode = rowNode->nextSibling()) {
qreal rowHeight = m_model->expandedRowHeight(row++); qreal rowHeight = d->model->expandedRowHeight(row++);
QMatrix4x4 matrix; QMatrix4x4 matrix;
matrix.translate(0, offset, 0); matrix.translate(0, offset, 0);
matrix.scale(1, rowHeight / TimelineModel::defaultRowHeight(), 1); matrix.scale(1, rowHeight / TimelineModel::defaultRowHeight(), 1);
@@ -275,18 +322,18 @@ QSGNode *TimelineRenderer::updatePaintNode(QSGNode *node,
} }
} }
m_modelDirty = false; d->modelDirty = false;
m_notesDirty = false; d->notesDirty = false;
m_rowCountsDirty = false; d->rowCountsDirty = false;
m_rowHeightsDirty = false; d->rowHeightsDirty = false;
m_lastState = state; d->lastState = state;
QSGNode *rowNode = m_model->expanded() ? state->expandedRowRoot() : state->collapsedRowRoot(); QSGNode *rowNode = d->model->expanded() ? state->expandedRowRoot() : state->collapsedRowRoot();
QSGNode *overlayNode = m_model->expanded() ? state->expandedOverlayRoot() : QSGNode *overlayNode = d->model->expanded() ? state->expandedOverlayRoot() :
state->collapsedOverlayRoot(); state->collapsedOverlayRoot();
QMatrix4x4 matrix; QMatrix4x4 matrix;
matrix.translate((state->start() - m_zoomer->windowStart()) * spacing, 0, 0); matrix.translate((state->start() - d->zoomer->windowStart()) * spacing, 0, 0);
matrix.scale(spacing / state->scale(), 1, 1); matrix.scale(spacing / state->scale(), 1, 1);
QSGTransformNode *transform = static_cast<QSGTransformNode *>(node); QSGTransformNode *transform = static_cast<QSGTransformNode *>(node);
@@ -305,14 +352,14 @@ void TimelineRenderer::mousePressEvent(QMouseEvent *event)
Q_UNUSED(event); Q_UNUSED(event);
} }
int TimelineRenderer::rowFromPosition(int y) int TimelineRenderer::TimelineRendererPrivate::rowFromPosition(int y) const
{ {
if (!m_model->expanded()) if (!model->expanded())
return y / TimelineModel::defaultRowHeight(); return y / TimelineModel::defaultRowHeight();
int ret = 0; int ret = 0;
for (int row = 0; row < m_model->expandedRowCount(); ++row) { for (int row = 0; row < model->expandedRowCount(); ++row) {
y -= m_model->expandedRowHeight(row); y -= model->expandedRowHeight(row);
if (y <= 0) return ret; if (y <= 0) return ret;
++ret; ++ret;
} }
@@ -322,9 +369,10 @@ int TimelineRenderer::rowFromPosition(int y)
void TimelineRenderer::mouseReleaseEvent(QMouseEvent *event) void TimelineRenderer::mouseReleaseEvent(QMouseEvent *event)
{ {
Q_D(TimelineRenderer);
Q_UNUSED(event); Q_UNUSED(event);
if (!m_model->isEmpty()) if (!d->model->isEmpty())
manageClicked(); d->manageClicked();
} }
void TimelineRenderer::mouseMoveEvent(QMouseEvent *event) void TimelineRenderer::mouseMoveEvent(QMouseEvent *event)
@@ -332,131 +380,161 @@ void TimelineRenderer::mouseMoveEvent(QMouseEvent *event)
event->setAccepted(false); event->setAccepted(false);
} }
void TimelineRenderer::hoverMoveEvent(QHoverEvent *event) void TimelineRenderer::hoverMoveEvent(QHoverEvent *event)
{ {
Q_D(TimelineRenderer);
Q_UNUSED(event); Q_UNUSED(event);
manageHovered(event->pos().x(), event->pos().y()); d->manageHovered(event->pos().x(), event->pos().y());
if (m_currentSelection.eventIndex == -1) if (d->currentSelection.eventIndex == -1)
event->setAccepted(false); event->setAccepted(false);
} }
void TimelineRenderer::manageClicked() void TimelineRenderer::TimelineRendererPrivate::manageClicked()
{ {
if (m_currentSelection.eventIndex != -1) { Q_Q(TimelineRenderer);
if (m_currentSelection.eventIndex == m_selectedItem) if (currentSelection.eventIndex != -1) {
setSelectionLocked(!m_selectionLocked); if (currentSelection.eventIndex == selectedItem)
q->setSelectionLocked(!selectionLocked);
else else
setSelectionLocked(true); q->setSelectionLocked(true);
// itemPressed() will trigger an update of the events and JavaScript views. Make sure the // itemPressed() will trigger an update of the events and JavaScript views. Make sure the
// correct event is already selected when that happens, to prevent confusion. // correct event is already selected when that happens, to prevent confusion.
setSelectedItem(m_currentSelection.eventIndex); q->setSelectedItem(currentSelection.eventIndex);
emit itemPressed(m_currentSelection.eventIndex); emit q->itemPressed(currentSelection.eventIndex);
} else { } else {
setSelectionLocked(false); q->setSelectionLocked(false);
setSelectedItem(-1); q->setSelectedItem(-1);
emit itemPressed(-1); emit q->itemPressed(-1);
} }
} }
void TimelineRenderer::manageHovered(int mouseX, int mouseY) void TimelineRenderer::TimelineRendererPrivate::manageHovered(int mouseX, int mouseY)
{ {
qint64 duration = m_zoomer->windowDuration(); Q_Q(TimelineRenderer);
qint64 duration = zoomer->windowDuration();
if (duration <= 0) if (duration <= 0)
return; return;
// Make the "selected" area 3 pixels wide by adding/subtracting 1 to catch very narrow events. // Make the "selected" area 3 pixels wide by adding/subtracting 1 to catch very narrow events.
qint64 startTime = (mouseX - 1) * duration / width() + m_zoomer->windowStart(); qint64 startTime = (mouseX - 1) * duration / q->width() + zoomer->windowStart();
qint64 endTime = (mouseX + 1) * duration / width() + m_zoomer->windowStart(); qint64 endTime = (mouseX + 1) * duration / q->width() + zoomer->windowStart();
qint64 exactTime = (startTime + endTime) / 2; qint64 exactTime = (startTime + endTime) / 2;
int row = rowFromPosition(mouseY); int row = rowFromPosition(mouseY);
// already covered? Only recheck selectionLocked and make sure m_selectedItem is correct. // already covered? Only recheck selectionLocked and make sure d->selectedItem is correct.
if (m_currentSelection.eventIndex != -1 && if (currentSelection.eventIndex != -1 &&
exactTime >= m_currentSelection.startTime && exactTime >= currentSelection.startTime &&
exactTime < m_currentSelection.endTime && exactTime < currentSelection.endTime &&
row == m_currentSelection.row) { row == currentSelection.row) {
if (!m_selectionLocked) if (!selectionLocked)
setSelectedItem(m_currentSelection.eventIndex); q->setSelectedItem(currentSelection.eventIndex);
return; return;
} }
// find if there's items in the time range // find if there's items in the time range
int eventFrom = m_model->firstIndex(startTime); int eventFrom = model->firstIndex(startTime);
int eventTo = m_model->lastIndex(endTime); int eventTo = model->lastIndex(endTime);
m_currentSelection.eventIndex = -1; currentSelection.eventIndex = -1;
if (eventFrom == -1 || eventTo < eventFrom || eventTo >= m_model->count()) if (eventFrom == -1 || eventTo < eventFrom || eventTo >= model->count())
return; return;
// find if we are in the right column // find if we are in the right column
qint64 bestOffset = std::numeric_limits<qint64>::max(); qint64 bestOffset = std::numeric_limits<qint64>::max();
for (int i=eventTo; i>=eventFrom; --i) { for (int i=eventTo; i>=eventFrom; --i) {
if ( m_model->row(i) == row) { if (model->row(i) == row) {
// There can be small events that don't reach the cursor position after large events // There can be small events that don't reach the cursor position after large events
// that do but are in a different row. // that do but are in a different row.
qint64 itemEnd = m_model->endTime(i); qint64 itemEnd = model->endTime(i);
if (itemEnd < startTime) if (itemEnd < startTime)
continue; continue;
qint64 itemStart = m_model->startTime(i); qint64 itemStart = model->startTime(i);
qint64 offset = qAbs(itemEnd - exactTime) + qAbs(itemStart - exactTime); qint64 offset = qAbs(itemEnd - exactTime) + qAbs(itemStart - exactTime);
if (offset < bestOffset) { if (offset < bestOffset) {
// match // match
m_currentSelection.eventIndex = i; currentSelection.eventIndex = i;
m_currentSelection.startTime = itemStart; currentSelection.startTime = itemStart;
m_currentSelection.endTime = itemEnd; currentSelection.endTime = itemEnd;
m_currentSelection.row = row; currentSelection.row = row;
bestOffset = offset; bestOffset = offset;
} }
} }
} }
if (!m_selectionLocked && m_currentSelection.eventIndex != -1) if (!selectionLocked && currentSelection.eventIndex != -1)
setSelectedItem(m_currentSelection.eventIndex); q->setSelectedItem(currentSelection.eventIndex);
} }
void TimelineRenderer::clearData() void TimelineRenderer::clearData()
{ {
resetCurrentSelection(); Q_D(TimelineRenderer);
d->resetCurrentSelection();
setSelectedItem(-1); setSelectedItem(-1);
setSelectionLocked(true); setSelectionLocked(true);
} }
void TimelineRenderer::setSelectedItem(int itemIndex)
{
Q_D(TimelineRenderer);
if (d->selectedItem != itemIndex) {
d->selectedItem = itemIndex;
update();
emit selectedItemChanged(itemIndex);
}
}
void TimelineRenderer::setSelectionLocked(bool locked)
{
Q_D(TimelineRenderer);
if (d->selectionLocked != locked) {
d->selectionLocked = locked;
update();
emit selectionLockedChanged(locked);
}
}
void TimelineRenderer::selectNextFromSelectionId(int selectionId) void TimelineRenderer::selectNextFromSelectionId(int selectionId)
{ {
setSelectedItem(m_model->nextItemBySelectionId(selectionId, m_zoomer->rangeStart(), Q_D(TimelineRenderer);
m_selectedItem)); setSelectedItem(d->model->nextItemBySelectionId(selectionId, d->zoomer->rangeStart(),
d->selectedItem));
} }
void TimelineRenderer::selectPrevFromSelectionId(int selectionId) void TimelineRenderer::selectPrevFromSelectionId(int selectionId)
{ {
setSelectedItem(m_model->prevItemBySelectionId(selectionId, m_zoomer->rangeStart(), Q_D(TimelineRenderer);
m_selectedItem)); setSelectedItem(d->model->prevItemBySelectionId(selectionId, d->zoomer->rangeStart(),
d->selectedItem));
} }
void TimelineRenderer::setModelDirty() void TimelineRenderer::setModelDirty()
{ {
m_modelDirty = true; Q_D(TimelineRenderer);
d->modelDirty = true;
update(); update();
} }
void TimelineRenderer::setRowHeightsDirty() void TimelineRenderer::setRowHeightsDirty()
{ {
m_rowHeightsDirty = true; Q_D(TimelineRenderer);
d->rowHeightsDirty = true;
update(); update();
} }
void TimelineRenderer::setNotesDirty() void TimelineRenderer::setNotesDirty()
{ {
m_notesDirty = true; Q_D(TimelineRenderer);
d->notesDirty = true;
update(); update();
} }
void TimelineRenderer::setRowCountsDirty() void TimelineRenderer::setRowCountsDirty()
{ {
m_rowCountsDirty = true; Q_D(TimelineRenderer);
d->rowCountsDirty = true;
update();
} }
} // namespace Timeline } // namespace Timeline

View File

@@ -56,28 +56,22 @@ public:
explicit TimelineRenderer(QQuickItem *parent = 0); explicit TimelineRenderer(QQuickItem *parent = 0);
bool selectionLocked() const bool selectionLocked() const;
{ int selectedItem() const;
return m_selectionLocked;
}
int selectedItem() const TimelineModel *model() const;
{
return m_selectedItem;
}
TimelineModel *model() const { return m_model; }
void setModel(TimelineModel *model); void setModel(TimelineModel *model);
TimelineZoomControl *zoomer() const { return m_zoomer; } TimelineZoomControl *zoomer() const;
void setZoomer(TimelineZoomControl *zoomer); void setZoomer(TimelineZoomControl *zoomer);
TimelineNotesModel *notes() const { return m_notes; } TimelineNotesModel *notes() const;
void setNotes(TimelineNotesModel *notes); void setNotes(TimelineNotesModel *notes);
bool modelDirty() const; bool modelDirty() const;
bool notesDirty() const; bool notesDirty() const;
bool rowHeightsDirty() const; bool rowHeightsDirty() const;
bool rowCountsDirty() const;
Q_INVOKABLE void selectNextFromSelectionId(int selectionId); Q_INVOKABLE void selectNextFromSelectionId(int selectionId);
Q_INVOKABLE void selectPrevFromSelectionId(int selectionId); Q_INVOKABLE void selectPrevFromSelectionId(int selectionId);
@@ -97,25 +91,9 @@ signals:
public slots: public slots:
void clearData(); void clearData();
void setSelectedItem(int itemIndex) void setSelectedItem(int itemIndex);
{ void setSelectionLocked(bool locked);
if (m_selectedItem != itemIndex) {
m_selectedItem = itemIndex;
update();
emit selectedItemChanged(itemIndex);
}
}
void setSelectionLocked(bool locked)
{
if (m_selectionLocked != locked) {
m_selectionLocked = locked;
update();
emit selectionLockedChanged(locked);
}
}
private slots:
void setModelDirty(); void setModelDirty();
void setRowHeightsDirty(); void setRowHeightsDirty();
void setNotesDirty(); void setNotesDirty();
@@ -129,38 +107,9 @@ protected:
virtual void hoverMoveEvent(QHoverEvent *event); virtual void hoverMoveEvent(QHoverEvent *event);
private: private:
int rowFromPosition(int y); class TimelineRendererPrivate;
TimelineRendererPrivate *d_ptr;
void manageClicked(); Q_DECLARE_PRIVATE(TimelineRenderer)
void manageHovered(int mouseX, int mouseY);
static const int SafeFloatMax = 1 << 12;
void resetCurrentSelection();
TimelineRenderState *findRenderState();
TimelineModel *m_model;
TimelineZoomControl *m_zoomer;
TimelineNotesModel *m_notes;
struct {
qint64 startTime;
qint64 endTime;
int row;
int eventIndex;
} m_currentSelection;
int m_selectedItem;
bool m_selectionLocked;
bool m_modelDirty;
bool m_rowHeightsDirty;
bool m_notesDirty;
bool m_rowCountsDirty;
QList<const TimelineRenderPass *> m_renderPasses;
QVector<QVector<TimelineRenderState *> > m_renderStates;
TimelineRenderState *m_lastState;
}; };
} // namespace Timeline } // namespace Timeline

View File

@@ -0,0 +1,83 @@
/****************************************************************************
**
** Copyright (C) 2014 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://www.qt.io/licensing. For further information
** use the contact form at http://www.qt.io/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 or version 3 as published by the Free
** Software Foundation and appearing in the file LICENSE.LGPLv21 and
** LICENSE.LGPLv3 included in the packaging of this file. Please review the
** following information to ensure the GNU Lesser General Public License
** requirements will be met: https://www.gnu.org/licenses/lgpl.html and
** http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
#ifndef TIMELINERENDERER_P_H
#define TIMELINERENDERER_P_H
#include "timelinerenderer.h"
namespace Timeline {
class TimelineRenderer::TimelineRendererPrivate {
public:
TimelineRendererPrivate(TimelineRenderer *q);
int rowFromPosition(int y) const;
void manageClicked();
void manageHovered(int mouseX, int mouseY);
static const int SafeFloatMax = 1 << 12;
void resetCurrentSelection();
TimelineRenderState *findRenderState();
TimelineModel *model;
TimelineZoomControl *zoomer;
TimelineNotesModel *notes;
struct {
qint64 startTime;
qint64 endTime;
int row;
int eventIndex;
} currentSelection;
int selectedItem;
bool selectionLocked;
bool modelDirty;
bool rowHeightsDirty;
bool notesDirty;
bool rowCountsDirty;
QList<const TimelineRenderPass *> renderPasses;
QVector<QVector<TimelineRenderState *> > renderStates;
TimelineRenderState *lastState;
private:
TimelineRenderer *q_ptr;
Q_DECLARE_PUBLIC(TimelineRenderer)
};
} // namespace Timeline
#endif // TIMELINERENDERER_P_H