Initial commit
This commit is contained in:
commit
b7d90b9afe
16245 files changed
+3396666
No files matched your search
@@ -0,0 +1,184 @@
|
||||
/**
|
||||
* @RDE_HEADER@
|
||||
* IntervalModel
|
||||
* $Id$
|
||||
* $HeadURL$
|
||||
* $Author$
|
||||
* Created by Christian Fröbel, SLSE, 2017-07-19
|
||||
*/
|
||||
|
||||
#include "interval_model.h"
|
||||
#include <AudioVideoManagement/av_helper.h>
|
||||
#include <QVariant>
|
||||
#include <QString>
|
||||
#include <QColor>
|
||||
#include <QModelIndex>
|
||||
#include <QDateTime>
|
||||
|
||||
namespace AudioVideoManagement
|
||||
{
|
||||
|
||||
IntervalModel::IntervalModel()
|
||||
: LtsAbstractTableModel({tr("Start"), tr("End"), tr("Duration [s]")}, nullptr)
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
QString IntervalModel::dateTimeToStringy(const QDateTime &dt) const
|
||||
{
|
||||
return QDateTime::fromMSecsSinceEpoch(dt.toMSecsSinceEpoch() + (m_timezoneHoursOffset * 3600 * 1000)).toString(QStringLiteral("dd.MM.yy HH:mm:ss.zzz"));
|
||||
}
|
||||
|
||||
|
||||
QString IntervalModel::msecsSinceEpochToStringy(qint64 msecs) const
|
||||
{
|
||||
return dateTimeToStringy(QDateTime::fromMSecsSinceEpoch(msecs));
|
||||
}
|
||||
|
||||
|
||||
void IntervalModel::setTimezoneHoursOffset(int timezoneHoursOffset)
|
||||
{
|
||||
m_timezoneHoursOffset = timezoneHoursOffset;
|
||||
emit dataChanged({}, {}, {Qt::DisplayRole}); // TODO: only affected columns !!
|
||||
}
|
||||
|
||||
|
||||
QVariant IntervalModel::data(const QModelIndex &index, int role) const
|
||||
{
|
||||
if (!index.isValid())
|
||||
return QVariant();
|
||||
|
||||
const AvaTimelinePart &interval = m_vecData.at(index.row());
|
||||
switch (role)
|
||||
{
|
||||
case Qt::DisplayRole:
|
||||
{
|
||||
switch (index.column())
|
||||
{
|
||||
case Start:
|
||||
return msecsSinceEpochToStringy(toMSecSinceEpoch(interval.first));
|
||||
case End:
|
||||
return msecsSinceEpochToStringy(toMSecSinceEpoch(interval.second));
|
||||
case Duration:
|
||||
{
|
||||
qint64 duration = (toMSecSinceEpoch(interval.second) - toMSecSinceEpoch(interval.first));
|
||||
|
||||
qint64 secs = duration / 1000;
|
||||
qint64 msecs = (duration % 1000);
|
||||
|
||||
return QStringLiteral("%1.%2").arg(secs).arg(msecs, 3, 10, QLatin1Char('0'));
|
||||
}
|
||||
}
|
||||
Q_ASSERT(false);
|
||||
break;
|
||||
}
|
||||
|
||||
case Qt::BackgroundRole:
|
||||
{
|
||||
if (m_currentInterval == (2 * index.row()))
|
||||
return QVariant(QColor(Qt::green));
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
void IntervalModel::reset()
|
||||
{
|
||||
m_currentPos.reset();
|
||||
m_currentInterval.reset();
|
||||
setData({});
|
||||
emit currentIntervalChanged(false, false, QModelIndex());
|
||||
}
|
||||
|
||||
/**
|
||||
* forceSignal == true is used in a reconnect scenario.
|
||||
* Then, we call this method with pos == m_currentPos but
|
||||
* rely on the currentIntervalChanged signal in order
|
||||
* to update the button states (backward and forward interval).
|
||||
*/
|
||||
void IntervalModel::setCurrentPosition(AvaTimePoint pos, bool forceSignal)
|
||||
{
|
||||
if (m_vecData.isEmpty()) // can happen after a reconnect
|
||||
return;
|
||||
|
||||
HalfIndex newInterval = intervalForPos(pos);
|
||||
bool intervalChanged = newInterval != m_currentInterval;
|
||||
m_currentPos = pos;
|
||||
m_currentInterval = newInterval;
|
||||
if (!intervalChanged && !forceSignal)
|
||||
return;
|
||||
|
||||
bool hasPrev = newInterval >= 0;
|
||||
bool hasNext = newInterval < 2 * (m_vecData.size() - 1);
|
||||
QModelIndex rowIndex;
|
||||
if (newInterval % 2 == 0)
|
||||
rowIndex = index(newInterval / 2, 0);
|
||||
emit currentIntervalChanged(hasPrev, hasNext, rowIndex);
|
||||
|
||||
QModelIndex topLeft = index(0, 0);
|
||||
QModelIndex bottomRight = index(rowCount() - 1, columnCount() - 1);
|
||||
emit dataChanged(topLeft, bottomRight, {Qt::BackgroundRole});
|
||||
}
|
||||
|
||||
const AvaTimelinePart &IntervalModel::previousInterval() const
|
||||
{
|
||||
Q_ASSERT(m_currentInterval);
|
||||
Q_ASSERT(*m_currentInterval != -1);
|
||||
|
||||
bool withinInterval = *m_currentInterval % 2 == 0;
|
||||
int intervalIndex = *m_currentInterval / 2;
|
||||
|
||||
if (!withinInterval)
|
||||
return m_vecData.at(intervalIndex);
|
||||
|
||||
|
||||
// Do something like in a CD player:
|
||||
// If we're a "good" time within the song, go to the beginning of the song.
|
||||
// Otherwise (if we're right at the beginning), go to the previous song.
|
||||
if (intervalIndex == 0)
|
||||
return m_vecData.at(intervalIndex);
|
||||
|
||||
const AvaTimelinePart &interval = m_vecData.at(intervalIndex);
|
||||
if (*m_currentPos > interval.first + std::chrono::seconds(2))
|
||||
return interval;
|
||||
else
|
||||
return m_vecData.at(intervalIndex - 1);
|
||||
}
|
||||
|
||||
const AvaTimelinePart &IntervalModel::nextInterval() const
|
||||
{
|
||||
Q_ASSERT(m_currentInterval);
|
||||
int intervalIndex = (*m_currentInterval + 2) / 2;
|
||||
return m_vecData.at(intervalIndex);
|
||||
}
|
||||
|
||||
IntervalModel::HalfIndex IntervalModel::intervalForPos(AvaTimePoint pos) const
|
||||
{
|
||||
Q_ASSERT(!m_vecData.isEmpty());
|
||||
|
||||
for (int i = 0; i < m_vecData.size(); ++i)
|
||||
{
|
||||
const AvaTimelinePart &interval = m_vecData.at(i);
|
||||
|
||||
if (pos < interval.first)
|
||||
{
|
||||
// position is between current and previous interval.
|
||||
return 2 * i - 1;
|
||||
}
|
||||
|
||||
if (pos >= interval.first && pos <= interval.second)
|
||||
{
|
||||
// found containing interval
|
||||
return 2 * i;
|
||||
}
|
||||
}
|
||||
|
||||
// position is after last interval
|
||||
return 2 * m_vecData.size() - 1;
|
||||
}
|
||||
|
||||
} // namespace AudioVideoManagement
|
||||
Reference in new issue
Block a user