Files
qt6-migration-pipeline/Lts/Common/LtsTimelineClassic/TimelineIndicator.cpp
T

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();
}
}