520 lines
11 KiB
C++
Executable File
520 lines
11 KiB
C++
Executable File
|
|
|
|
|
|
#include "TimelineWidget.h"
|
|
#include "TimelineIndicator.h"
|
|
#include "EventTools.h"
|
|
|
|
#include <NGLLogger/NGLLoggerBootstrap.h>
|
|
|
|
#include <ngltools/ngltools_dtg.h>
|
|
|
|
#include <QGuiApplication>
|
|
#include <QHeaderView>
|
|
#include <QFont>
|
|
#include <QFontMetrics>
|
|
#include <QPainter>
|
|
#include <QPalette>
|
|
#include <QPushButton>
|
|
#include <QApplication>
|
|
#include <QHBoxLayout>
|
|
#include <QDateTime>
|
|
#include <QPoint>
|
|
#include <QLabel>
|
|
#include <QComboBox>
|
|
|
|
#include <QDebug>
|
|
|
|
|
|
|
|
#ifdef LTS_DEBUG
|
|
|
|
#endif
|
|
#ifdef VERBOSE
|
|
#define dbg_print(x) qWarning() << #x << x
|
|
#else
|
|
#define dbg_print(x) (void)x;
|
|
#endif
|
|
|
|
namespace LtsTimelineClassic
|
|
{
|
|
|
|
TimelineIndicator::TimelineIndicator(QWidget *parent)
|
|
: QWidget(parent)
|
|
, m_zoomFactorPoints(0)
|
|
, m_pbZoom(new QPushButton(this))
|
|
, m_pbUnzoom(new QPushButton(this))
|
|
, m_cbZoomLevel(new QComboBox(this))
|
|
, m_currentTextHeight(0)
|
|
, m_currentTextWidth(0)
|
|
, m_sectionPos(0)
|
|
, m_sectionSize(0)
|
|
, m_logger(NGL::NGLLoggerBootstrap::getNGLRootLogger().getNGLLogger("Timeline.Indicator"))
|
|
{
|
|
m_timeArray.reserve(11 + 11 + 7 + 10);
|
|
|
|
m_timeArray <<
|
|
|
|
1 << 2 << 3 << 4 << 5 << 6 << 12 << 15 << 20 << 30 << 60 <<
|
|
|
|
|
|
1 * 60 << 2 * 60 << 3 * 60 << 4 * 60 << 5 * 60 << 6 * 60 << 12 * 60 << 15 * 60 << 20 * 60 << 30 * 60 << 60 * 60 <<
|
|
|
|
|
|
1 * 60 * 60 << 2 * 60 * 60 << 4 * 60 * 60 << 6 * 60 * 60 << 8 * 60 * 60 << 12 * 60 * 60 << 24 * 60 * 60 <<
|
|
|
|
|
|
1 * 60 * 60 << 2 * 60 * 60 << 4 * 60 * 60 << 6 * 60 * 60 << 8 * 60 * 60 << 10 * 60 * 60 << 14 * 60 * 60 << 18 * 60 * 60 << 22 * 60 * 60 << 26 * 60 * 60 << 30 * 60 * 60;
|
|
|
|
QHBoxLayout *centralLayout = new QHBoxLayout();
|
|
centralLayout->setSpacing(0);
|
|
|
|
setLayout(centralLayout);
|
|
|
|
m_pbZoom->setText(QLatin1String("+"));
|
|
m_pbZoom->setFixedSize(s_pbSize, s_pbSize);
|
|
|
|
m_pbUnzoom->setText(QLatin1String("-"));
|
|
m_pbUnzoom->setFixedSize(s_pbSize, s_pbSize);
|
|
|
|
|
|
m_cbZoomLevel->addItem(tr("10 min"), 600);
|
|
m_cbZoomLevel->addItem(tr("30 min"), 1800);
|
|
m_cbZoomLevel->addItem(tr("1 h"), 3600);
|
|
m_cbZoomLevel->addItem(tr("2 h"), 7200);
|
|
m_cbZoomLevel->addItem(tr("4 h"), 14400);
|
|
m_cbZoomLevel->addItem(tr("8 h"), 28800);
|
|
|
|
m_cbZoomLevel->setCurrentIndex(0);
|
|
|
|
m_cbZoomLevel->setFixedHeight(s_pbSize);
|
|
m_zoomFactorPoints = m_cbZoomLevel->currentData().toLongLong();
|
|
|
|
connect(m_cbZoomLevel, &QComboBox::currentTextChanged,
|
|
this, &TimelineIndicator::afterZoom);
|
|
connect(m_pbZoom, &QPushButton::clicked,
|
|
this, &TimelineIndicator::slotZoom);
|
|
connect(m_pbUnzoom, &QPushButton::clicked,
|
|
this, &TimelineIndicator::slotUnzoom);
|
|
connect(this, &TimelineIndicator::signalAddLine,
|
|
this, &TimelineIndicator::slotAddLine);
|
|
connect(this, &TimelineIndicator::signalResetLineList,
|
|
this, &TimelineIndicator::slotResetLineList);
|
|
|
|
centralLayout->addWidget(m_pbZoom, 0, Qt::AlignLeft | Qt::AlignTop);
|
|
centralLayout->addWidget(m_pbUnzoom, 0, Qt::AlignLeft | Qt::AlignTop);
|
|
centralLayout->addWidget(m_cbZoomLevel, 1, Qt::AlignLeft | Qt::AlignTop);
|
|
|
|
|
|
|
|
|
|
|
|
QFontMetrics fm(QApplication::font());
|
|
m_currentTextHeight = fm.height();
|
|
|
|
#if QT_VERSION < QT_VERSION_CHECK(5, 11, 0)
|
|
m_currentTextWidth = fm.width(DTG::toString(QDateTime::currentDateTimeUtc(), DTG::Short));
|
|
#else
|
|
m_currentTextWidth = fm.horizontalAdvance(DTG::toString(QDateTime::currentDateTimeUtc(), DTG::Short));
|
|
#endif
|
|
|
|
dbg_print(m_currentTextWidth);
|
|
|
|
|
|
}
|
|
|
|
TimelineIndicator::~TimelineIndicator()
|
|
{
|
|
|
|
}
|
|
|
|
void TimelineIndicator::afterZoom()
|
|
{
|
|
m_zoomFactorPoints = m_cbZoomLevel->currentData().toLongLong() * 1000;
|
|
emit signalSetZoomFactor(m_zoomFactorPoints);
|
|
update();
|
|
}
|
|
|
|
|
|
void TimelineIndicator::slotZoom()
|
|
{
|
|
int pos = m_cbZoomLevel->currentIndex();
|
|
|
|
if (pos == 0)
|
|
return;
|
|
|
|
m_cbZoomLevel->setCurrentIndex(pos - 1);
|
|
emit signalZoomChanged();
|
|
}
|
|
|
|
void TimelineIndicator::slotUnzoom()
|
|
{
|
|
int count = m_cbZoomLevel->count();
|
|
int pos = m_cbZoomLevel->currentIndex();
|
|
|
|
if (pos >= count - 1)
|
|
return;
|
|
|
|
m_cbZoomLevel->setCurrentIndex(pos + 1);
|
|
emit signalZoomChanged();
|
|
}
|
|
|
|
enum highestUnit
|
|
{
|
|
HU_INVALID,
|
|
|
|
HU_DAYS,
|
|
HU_HOURS,
|
|
HU_MINUTES,
|
|
HU_SECONDS
|
|
};
|
|
|
|
void TimelineIndicator::refreshData()
|
|
{
|
|
#ifdef VERBOSE
|
|
qWarning() << "<refreshData>";
|
|
#endif
|
|
|
|
|
|
|
|
emit signalResetLineList();
|
|
|
|
#ifdef VERBOSE
|
|
qWarning() << "section x" << m_sectionPos << "length" << m_sectionSize;
|
|
#endif
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
double abstand = m_sectionPos + m_currentTextWidth + s_TimeTextDistanceTolerancePixels;
|
|
dbg_print(abstand);
|
|
|
|
|
|
|
|
qint64 eventTimeOfAbstand = EventTools::getEventTime(abstand);
|
|
dbg_print(eventTimeOfAbstand);
|
|
qint64 adjustedMin = EventTools::getAdjustedMin();
|
|
dbg_print(adjustedMin);
|
|
qint64 textWidthTime = (eventTimeOfAbstand - adjustedMin);
|
|
|
|
if (textWidthTime < 0)
|
|
{
|
|
qWarning() << "TimelineIndicator: paintEvent: textWidthTime invalid! (" << textWidthTime << ")";
|
|
return;
|
|
}
|
|
|
|
qint64 eventTime = EventTools::getEventTime(abstand);
|
|
dbg_print(eventTime);
|
|
|
|
|
|
QDateTime textWidthDt = QDateTime::fromMSecsSinceEpoch(textWidthTime);
|
|
|
|
|
|
|
|
int days = textWidthDt.date().day() - 1;
|
|
int hours = textWidthDt.time().hour() - 1;
|
|
int minutes = textWidthDt.time().minute();
|
|
int seconds = textWidthDt.time().second() - 1;
|
|
|
|
highestUnit unit = HU_INVALID;
|
|
|
|
if (days == 0)
|
|
if (hours == 0)
|
|
if (minutes == 0)
|
|
if (seconds == 0)
|
|
{
|
|
#ifdef VERBOSE
|
|
qWarning() << "refreshData: no lower time unit available" ;
|
|
#endif
|
|
return;
|
|
}
|
|
else
|
|
{
|
|
|
|
unit = HU_SECONDS;
|
|
}
|
|
else
|
|
{
|
|
|
|
unit = HU_MINUTES;
|
|
}
|
|
else
|
|
{
|
|
|
|
unit = HU_HOURS;
|
|
}
|
|
else
|
|
{
|
|
|
|
unit = HU_DAYS;
|
|
}
|
|
|
|
if (unit == HU_INVALID)
|
|
{
|
|
#ifdef VERBOSE
|
|
qWarning() << "unit == HU_INVALID";
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
int higherValue = 0;
|
|
for (int i = 0; i < m_timeArray.size(); i++)
|
|
{
|
|
qint64 time = (m_timeArray[i] * 1000);
|
|
|
|
if (time >= textWidthTime)
|
|
{
|
|
higherValue = time;
|
|
|
|
break;
|
|
}
|
|
else
|
|
{
|
|
continue;
|
|
}
|
|
|
|
|
|
|
|
#ifdef VERBOSE
|
|
qWarning() << "refreshData: no fitting highest unit found !" ;
|
|
#endif
|
|
return;
|
|
}
|
|
|
|
|
|
if (higherValue < 1)
|
|
{
|
|
|
|
return;
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
QDateTime minDt = QDateTime::fromMSecsSinceEpoch(adjustedMin);
|
|
dbg_print(minDt);
|
|
dbg_print(unit);
|
|
|
|
switch (unit)
|
|
{
|
|
case HU_SECONDS:
|
|
{
|
|
minDt = minDt.addSecs(-(minDt.time().second()));
|
|
#ifdef VERBOSE
|
|
qCritical() << "HU_SECONDS";
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case HU_MINUTES:
|
|
{
|
|
minDt = minDt.addSecs(-(minDt.time().second()));
|
|
minDt = minDt.addSecs(-(minDt.time().minute() * 60));
|
|
#ifdef VERBOSE
|
|
qCritical() << "HU_MINUTES";
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case HU_HOURS:
|
|
{
|
|
minDt = minDt.addSecs(-(minDt.time().second()));
|
|
minDt = minDt.addSecs(-(minDt.time().minute() * 60));
|
|
minDt = minDt.addSecs(-(minDt.time().hour() * 60 * 60));
|
|
#ifdef VERBOSE
|
|
qCritical() << "HU_HOURS";
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
case HU_DAYS:
|
|
{
|
|
minDt = minDt.addSecs(-(minDt.time().second()));
|
|
minDt = minDt.addSecs(-(minDt.time().minute() * 60));
|
|
minDt = minDt.addSecs(-(minDt.time().hour() * 60 * 60));
|
|
minDt = minDt.addDays(-(minDt.date().day()));
|
|
#ifdef VERBOSE
|
|
qCritical() << "HU_DAYS";
|
|
#endif
|
|
|
|
break;
|
|
}
|
|
|
|
default:
|
|
{
|
|
#ifdef VERBOSE
|
|
qWarning() << "unit / scaling is off da charz !";
|
|
#endif
|
|
return;
|
|
}
|
|
}
|
|
|
|
dbg_print(minDt);
|
|
|
|
|
|
minDt = minDt.addMSecs(-higherValue);
|
|
|
|
dbg_print(minDt);
|
|
|
|
|
|
qint64 maxTimelineView = EventTools::getAdjustedMax() + (higherValue );
|
|
qint64 additional = textWidthTime / 2;
|
|
maxTimelineView += additional;
|
|
|
|
qint64 minTimeline = minDt.toMSecsSinceEpoch();
|
|
|
|
dbg_print(minTimeline);
|
|
dbg_print(maxTimelineView);
|
|
dbg_print(higherValue);
|
|
|
|
qint64 steps = (maxTimelineView - minTimeline) / higherValue;
|
|
if (steps < 0)
|
|
steps = steps * (-1);
|
|
|
|
if (steps > 60000 || steps < 1)
|
|
{
|
|
ERROR_LOG(m_logger) << "More than 60000 ("<<steps<<") or less than 1 lines to draw. Loop will exit after 60000 lines.";
|
|
}
|
|
|
|
if (steps < 1)
|
|
steps = 2;
|
|
|
|
uint16_t currentStep = 0;
|
|
|
|
dbg_print(steps);
|
|
|
|
|
|
for (qint64 indicatorTime = minTimeline;
|
|
indicatorTime < maxTimelineView + 1 ;
|
|
indicatorTime += higherValue)
|
|
|
|
{
|
|
if (currentStep > 60000)
|
|
break;
|
|
|
|
currentStep++;
|
|
|
|
int pos = EventTools::getEventPosition(indicatorTime);
|
|
dbg_print(indicatorTime);
|
|
|
|
if (pos + (m_currentTextWidth / 4) + 1 < m_sectionPos)
|
|
{
|
|
#ifdef VERBOSE
|
|
qCritical() << "Indicator: pos" << pos << "invisible #1";
|
|
#endif
|
|
continue;
|
|
}
|
|
else
|
|
if (pos - (m_currentTextWidth ) > (m_sectionPos + m_sectionSize))
|
|
{
|
|
#ifdef VERBOSE
|
|
qCritical() << "Indicator: pos" << pos << "invisible #2";
|
|
#endif
|
|
continue;
|
|
}
|
|
else
|
|
{
|
|
#ifdef VERBOSE
|
|
qCritical() << "Indicator: OKAY!! pos" << pos << "visible";
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
emit signalAddLine(pos, indicatorTime);
|
|
}
|
|
|
|
dbg_print(currentStep);
|
|
|
|
QFontMetrics fm(QApplication::font());
|
|
m_currentTextHeight = fm.height();
|
|
|
|
update();
|
|
}
|
|
|
|
void TimelineIndicator::paintEvent(QPaintEvent *)
|
|
{
|
|
|
|
|
|
QPainter painter(this);
|
|
painter.save();
|
|
painter.setClipping(true);
|
|
painter.setClipRect(QRect(x() - 8 + m_sectionPos, 0, m_sectionSize, height()));
|
|
|
|
#ifdef VERBOSE
|
|
int textY = (height() - m_currentTextHeight - 5);
|
|
#endif
|
|
|
|
int h = height();
|
|
|
|
for (auto i = m_lineMap.constBegin(); i != m_lineMap.constEnd(); ++i)
|
|
{
|
|
|
|
|
|
int pos = i.key();
|
|
|
|
|
|
painter.setPen(QPen(QColor("black"), 1.0));
|
|
painter.drawLine(pos, m_currentTextHeight, pos, h);
|
|
|
|
int centeredPos = pos - (m_currentTextWidth / 2);
|
|
qint64 time = (*i);
|
|
|
|
|
|
|
|
|
|
painter.drawText(centeredPos, (m_currentTextHeight / 2) + 4,
|
|
DTG::toStringMSec(time, DTG::Short));
|
|
|
|
#ifdef VERBOSE
|
|
WARNING_LOG(m_logger) << "paintEvent: actual drawing position: x=" << centeredPos << " y=" << textY;
|
|
#endif
|
|
}
|
|
|
|
painter.restore();
|
|
|
|
|
|
}
|
|
|
|
void TimelineIndicator::slotSectionResized(int logicalIndex, int oldSize, int newSize)
|
|
{
|
|
(void)oldSize;
|
|
|
|
|
|
QHeaderView *header = qobject_cast<QHeaderView *>(QObject::sender());
|
|
|
|
if (!header)
|
|
return;
|
|
|
|
if (logicalIndex == 1)
|
|
{
|
|
m_sectionPos = header->sectionPosition(1);
|
|
m_sectionSize = newSize;
|
|
|
|
}
|
|
|
|
update();
|
|
}
|
|
|
|
void TimelineIndicator::slotAddLine(double posX, qint64 time)
|
|
{
|
|
#ifdef VERBOSE
|
|
qCritical() << "slotAddLine: posX" << posX << "time" << time;
|
|
#endif
|
|
m_lineMap.insert(posX, time);
|
|
}
|
|
|
|
void TimelineIndicator::slotResetLineList()
|
|
{
|
|
m_lineMap.clear();
|
|
}
|
|
|
|
}
|