Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
+412
@@ -0,0 +1,412 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* MVC view (QTreeView) - shows items (rows), events, date-time lines and more
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Mike Wille, SLSE, 2014-10-01
|
||||
*/
|
||||
|
||||
#include "TimelineView.h"
|
||||
#include "TimelineHeaderView.h"
|
||||
#include "TimelineWidget.h"
|
||||
#include "EventDelegate.h"
|
||||
#include "EventGraphic.h"
|
||||
|
||||
#include <QPainter>
|
||||
#include <QPen>
|
||||
#include <QBrush>
|
||||
#include <QGuiApplication>
|
||||
#include <QHeaderView>
|
||||
#include <QHelpEvent>
|
||||
#include <QModelIndex>
|
||||
#include <QRect>
|
||||
#include <QDebug>
|
||||
|
||||
|
||||
namespace LtsTimelineClassic
|
||||
{
|
||||
|
||||
//TimelineView::TimelineView(TimelineHeaderView* headerView, QWidget *parent) :
|
||||
TimelineView::TimelineView(QWidget *parent)
|
||||
: QTreeView(parent)
|
||||
//, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Timeline.View"))
|
||||
, m_model(nullptr)
|
||||
, m_drawCache(false)
|
||||
{
|
||||
m_posMarkTime = 0; // invalid - do not draw
|
||||
|
||||
//setMouseTracking(true);
|
||||
setAlternatingRowColors(true); // so we can differ between specific rows
|
||||
setEditTriggers(QAbstractItemView::NoEditTriggers);
|
||||
setSelectionBehavior(QAbstractItemView::SelectItems);
|
||||
setSelectionMode(QAbstractItemView::NoSelection);
|
||||
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); // no horizontal scroll bar, because the TimelineWidget manages this and events are only virtually drawn on the view
|
||||
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn);
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::setHeader(QHeaderView *header)
|
||||
{
|
||||
if (header)
|
||||
{
|
||||
QTreeView::setHeader(header); // cannot use a member attribute, because setHeader takes ownership of given header, very cautious! please use qobject_cast when TimelineHeaderView needed
|
||||
header->setMinimumSectionSize(150); // minimum size for visualisation issues
|
||||
}
|
||||
else
|
||||
{
|
||||
//qDebug() << "ERROR: invalid header!";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
AbstractTimelineModel *TimelineView::timelineModel()
|
||||
{
|
||||
return m_model;
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::setTimelineModel(AbstractTimelineModel *model)
|
||||
{
|
||||
m_model = model;
|
||||
setMouseTracking(true); // if it is not enabled by default
|
||||
setModel(m_model);
|
||||
|
||||
EventDelegate *ed = new EventDelegate(this);
|
||||
|
||||
EventTools::setSectionHeight(ed->sizeHint().height());
|
||||
|
||||
setItemDelegate(ed); // a delegate, only for column 1 (events-column)
|
||||
}
|
||||
|
||||
|
||||
EventGraphic *TimelineView::getEventOnPosition(QPoint position)
|
||||
{
|
||||
position = viewport()->mapFromGlobal(position);
|
||||
QModelIndex index = indexAt(position);
|
||||
|
||||
if (index.isValid() && position.x() > header()->sectionSize(0)) // do not allow clicking on section 0
|
||||
{
|
||||
Item *item = static_cast<Item *>(index.internalPointer());
|
||||
|
||||
if (!item)
|
||||
return nullptr;
|
||||
|
||||
qint64 curTime = EventTools::getEventTime(position.x());
|
||||
EventGraphicList egl = item->getCurrentEGLFromPevcon(); // must be the current egl from pevcon (not eventlist), as events can be grouped (stacked events)
|
||||
|
||||
qint64 blockSizeTime = EventTools::getBlockSizeTime();
|
||||
|
||||
for (int i = 0; i < egl.count(); i++)
|
||||
{
|
||||
EventGraphic *eg = egl.at(i);
|
||||
|
||||
if (!eg)
|
||||
continue;
|
||||
|
||||
qint64 eventStartTime = eg->lowestTime();
|
||||
|
||||
if (eventStartTime == 0)
|
||||
continue;
|
||||
|
||||
qint64 eventEndTime = eventStartTime;
|
||||
|
||||
qint64 eglDuration = eg->getDuration();
|
||||
|
||||
if (eglDuration > blockSizeTime)
|
||||
eventEndTime += eglDuration;
|
||||
else
|
||||
eventEndTime += blockSizeTime;
|
||||
|
||||
if (curTime >= eventStartTime && curTime <= eventEndTime)
|
||||
return eg;
|
||||
}
|
||||
}
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
|
||||
bool TimelineView::event(QEvent *event)
|
||||
{
|
||||
switch (event->type())
|
||||
{
|
||||
case QEvent::ToolTip:
|
||||
{
|
||||
//emit signalEventAction(getEventOnPosition(((QHelpEvent*)static_cast<QHelpEvent*>(event))->globalPos()), EventGraphic::ACTION_TOOLTIP);
|
||||
|
||||
QHelpEvent *helpEvent = static_cast<QHelpEvent *>(event);
|
||||
|
||||
if (!helpEvent)
|
||||
return true;
|
||||
|
||||
EventGraphic *eg = getEventOnPosition(helpEvent->globalPos());
|
||||
|
||||
if (!eg)
|
||||
return true;
|
||||
|
||||
emit signalEventAction(eg, EventGraphic::ACTION_TOOLTIP);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return QTreeView::event(event); // otherwise...
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::wheelEvent(QWheelEvent *event)
|
||||
{
|
||||
QTreeView::wheelEvent(event);
|
||||
|
||||
if (QGuiApplication::queryKeyboardModifiers() != Qt::ControlModifier) // only scroll when CTRL is pressed
|
||||
return;
|
||||
|
||||
int scrolls = event->delta() / 120;
|
||||
|
||||
if (scrolls > 0)
|
||||
{
|
||||
for (int i = 0; i < scrolls; i++)
|
||||
emit signalZoom();
|
||||
}
|
||||
|
||||
if (scrolls < 0)
|
||||
{
|
||||
for (int i = 0; i > scrolls; i--)
|
||||
emit signalUnzoom();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::mouseReleaseEvent(QMouseEvent *event)
|
||||
{
|
||||
QTreeView::mouseReleaseEvent(event);
|
||||
|
||||
QPoint position = event->globalPos();
|
||||
EventGraphic *eg = getEventOnPosition(position);
|
||||
|
||||
if (!eg)
|
||||
return;
|
||||
|
||||
switch (event->button())
|
||||
{
|
||||
case Qt::LeftButton:
|
||||
{
|
||||
emit signalEventAction(eg, EventGraphic::ACTION_LEFT_CLICKED);
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::RightButton:
|
||||
{
|
||||
emit signalEventAction(eg, EventGraphic::ACTION_RIGHT_CLICKED);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
{
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::slotAddLine(int posX, qint64 time) // add posX to a list, so that the view can draw them on itself
|
||||
{
|
||||
//m_lineList.append(QPair<double, qint64>(posX, time));
|
||||
m_lineMap.insert(posX, time); // HACK! position as key, so only one line per position (which is perfectly okay and speedy)
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::slotResetLineList()
|
||||
{
|
||||
m_lineMap.clear();
|
||||
}
|
||||
|
||||
|
||||
/*void TimelineView::slotSetPosMarkPos(int posMarkPos) // hint: must be INT, because it's the position as PIXELS (not time as qint64)
|
||||
{
|
||||
//int sectionSize = this->header()->sectionSize(1);
|
||||
//QRect sectionRect(0, 0, sectionSize, 0); // only width matters for calculating a pixel position dependent on a fixed position
|
||||
|
||||
qint64 posMarkTime = EventTools::getEventTime(posMarkPos);
|
||||
m_posMarkTime = posMarkTime;
|
||||
|
||||
TimelineHeaderView* headerView = qobject_cast<TimelineHeaderView*>(header());
|
||||
if (headerView)
|
||||
{
|
||||
headerView->setPosMarkTime(posMarkTime);
|
||||
}
|
||||
|
||||
refreshData();
|
||||
}*/
|
||||
|
||||
|
||||
void TimelineView::slotSetPosMarkTime(qint64 posMarkTime) // does not have to be a slot anymore !!
|
||||
{
|
||||
m_posMarkTime = posMarkTime;
|
||||
|
||||
TimelineHeaderView *headerView = qobject_cast<TimelineHeaderView *>(header());
|
||||
if (headerView)
|
||||
headerView->setPosMarkTime(posMarkTime);
|
||||
|
||||
refreshData();
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::refreshData()
|
||||
{
|
||||
update();
|
||||
viewport()->update();
|
||||
}
|
||||
|
||||
|
||||
void TimelineView::paintEvent(QPaintEvent *event) // draw lines to show where next texts are
|
||||
{
|
||||
if (!m_model) // cannot draw without a model
|
||||
return;
|
||||
|
||||
QWidget *viewp0rt = viewport();
|
||||
|
||||
//qWarning() << "viewp0rt ptr" << (unsigned long long)viewp0rt;
|
||||
|
||||
QPainter painter(viewp0rt);
|
||||
|
||||
if (!painter.isActive())
|
||||
{
|
||||
//qWarning() << "painter not active";
|
||||
}
|
||||
|
||||
painter.save();
|
||||
|
||||
int viewPortHeight = viewp0rt->height();
|
||||
|
||||
QHeaderView *head0r = header();
|
||||
|
||||
//qWarning() << "head0r ptr" << (unsigned long long)head0r;
|
||||
|
||||
int sectionPos = head0r->sectionPosition(1);
|
||||
int sectionSize = head0r->sectionSize(1);
|
||||
|
||||
int minSection = sectionPos; // minimum x position
|
||||
int maxSection = minSection + sectionSize; // maximum x position
|
||||
|
||||
|
||||
//QRect paintRect(head0r->sectionPosition(1), 0,
|
||||
// head0r->sectionSize(1), height());
|
||||
QRect paintRect(minSection, 0,
|
||||
maxSection - minSection, height());
|
||||
painter.setClipping(true);
|
||||
painter.setClipRect(paintRect);
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
// draw date text lines first, can be overdrawn
|
||||
//for (int i = 0; i < m_lineList.count(); i++)
|
||||
for (auto i = m_lineMap.constBegin(); i != m_lineMap.constEnd(); ++i)
|
||||
{
|
||||
int pos = i.key(); //m_lineList.at(i).first;
|
||||
|
||||
painter.setPen(QPen(QBrush(QGuiApplication::palette().shadow()), 1.0));
|
||||
|
||||
if (pos > minSection &&
|
||||
pos < maxSection) // do not draw if out of view
|
||||
painter.drawLine(pos, 0, pos, viewPortHeight);
|
||||
else
|
||||
{
|
||||
#ifdef VERBOSE
|
||||
qCritical() << "out of view => pos" << pos << "min" << minSection << "max" << maxSection;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// workaround for date text lines: first draw lines, then draw containers (which are transparent)
|
||||
painter.restore();
|
||||
QTreeView::paintEvent(event);
|
||||
painter.save();
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
if (m_drawCache)
|
||||
{
|
||||
// draw gray bg (indicate uncached ranges)
|
||||
painter.setPen(QPen(QBrush("gray"), 1));
|
||||
painter.setBrush(QBrush("gray"));
|
||||
painter.drawRect(minSection, 0, maxSection, height());
|
||||
|
||||
|
||||
// draw cached ranges
|
||||
painter.setPen(QPen(QBrush("white"), 1));
|
||||
painter.setBrush(QBrush("white"));
|
||||
int h = height();
|
||||
|
||||
for (const auto &range : qAsConst(m_knownRanges))
|
||||
{
|
||||
int start = EventTools::getEventPosition(range.start);
|
||||
|
||||
if (start < minSection)
|
||||
start = minSection;
|
||||
|
||||
int end = EventTools::getEventPosition(range.end);
|
||||
|
||||
if (end > maxSection)
|
||||
end = maxSection;
|
||||
|
||||
painter.drawRect(start, 0, end - start, h);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
// draw marker lines
|
||||
// QRect areaRect(sectionPos, viewp0rt->x(),
|
||||
// sectionSize, height());
|
||||
|
||||
|
||||
//EventTools::setValues(m_min, m_max, m_sbPos, m_zoomFactor); // DO NOT SET VALUES HERE!!! Because old values are needed, plus this saves CPU & RAM
|
||||
|
||||
ItemList il = m_model->getRootItem()->getFullItemList(true);
|
||||
for (int i = 0; i < il.count(); i++)
|
||||
{
|
||||
if (il.at(i)->getName() == tr("Markers"))
|
||||
EventTools::drawMarkLines(&painter, il.at(i)->getFullEventList(true), height());//, areaRect);
|
||||
}
|
||||
|
||||
|
||||
//QRect sectionRect(0, 0, header()->sectionSize(1), 0);
|
||||
// draw pos mark line - is more important than a marker line
|
||||
if (m_posMarkTime > 0) // != 0
|
||||
{
|
||||
int posMarkPosition = EventTools::getEventPosition(m_posMarkTime); // pretend that the posMark is an event, does not matter
|
||||
|
||||
if (posMarkPosition > sectionPos &&
|
||||
posMarkPosition < sectionSize + sectionPos)
|
||||
{
|
||||
painter.setPen(QPen(QGuiApplication::palette().highlight(), 1.0));
|
||||
int xpos = posMarkPosition;// + sectionPos;
|
||||
painter.drawLine(xpos, 0, xpos, height());
|
||||
}
|
||||
}
|
||||
|
||||
painter.restore();
|
||||
|
||||
//event->ignore();
|
||||
}
|
||||
|
||||
}
|
||||
Reference in new issue
Block a user