Inspired by #42: display insertion date relative

Easy to find the most recent entry, because it says
"3 seconds ago"
This commit is contained in:
Christian Hohnstaedt 2018-06-25 21:15:48 +02:00
parent 5ff5d77d68
commit b10b4f7a53
12 changed files with 172 additions and 10 deletions

View File

@ -22,6 +22,8 @@
#define UTC_FORMAT "yyMMddHHmmss'Z'"
#define GEN_FORMAT "yy" UTC_FORMAT
#define TR QObject::tr
bool a1time::isUndefined() const
{
return toTime_t() == 0;
@ -151,9 +153,9 @@ a1time &a1time::set(const ASN1_TIME *a)
QString a1time::toString(QString fmt, Qt::TimeSpec spec) const
{
if (isUndefined())
return QObject::tr("Undefined");
return TR("Undefined");
if (!isValid())
return QObject::tr("Broken / Invalid");
return TR("Broken / Invalid");
return (spec == Qt::UTC ? toUTC() : toLocalTime()).toString(fmt);
}
@ -182,6 +184,41 @@ QString a1time::toPlain(const QString &fmt) const
return toString(fmt.isEmpty() ? GEN_FORMAT : fmt);
}
qint64 a1time::age() const
{
return secsTo(now());
}
QString a1time::toFancy() const
{
QString fmt("Dunno");
qint64 diff = age();
bool future = false;
if (diff < 0) {
future = true;
diff *= -1;
}
if (diff < 2 * SECS_PER_MINUTE) {
fmt = future ? TR("in %1 seconds") : TR("%1 seconds ago");
} else if (diff < 2 *SECS_PER_HOUR) {
diff /= SECS_PER_MINUTE;
fmt = future ? TR("in %1 minutes") : TR("%1 minutes ago");
} else if (diff < 2 *SECS_PER_DAY) {
diff /= SECS_PER_HOUR;
fmt = future ? TR("in %1 hours") : TR("%1 hours ago");
} else if (diff < 2 *SECS_PER_WEEK) {
diff /= SECS_PER_DAY;
fmt = future ? TR("in %1 days") : TR("%1 days ago");
} else if (diff < 2 *SECS_PER_MONTH) {
diff /= SECS_PER_WEEK;
fmt = future ? TR("in %1 weeks") : TR("%1 weeks ago");
} else {
diff /= SECS_PER_MONTH;
fmt = future ? TR("in %1 months") : TR("%1 months ago");
}
return fmt.arg(diff);
}
QString a1time::toPlainUTC() const
{
return toPlain(UTC_FORMAT);

View File

@ -12,7 +12,14 @@
#include <QDateTime>
#include <openssl/asn1.h>
#define SECONDS_PER_DAY (60*60*24)
#define SECS_PER_MINUTE (60)
#define SECS_PER_HOUR (SECS_PER_MINUTE *60)
#define SECS_PER_DAY (SECS_PER_HOUR*24)
#define SECS_PER_WEEK (SECS_PER_DAY*7)
#define SECS_PER_MONTH (SECS_PER_DAY*30)
#define MSECS_PER_MINUTE (SECS_PER_MINUTE*1000)
#define MSECS_PER_HOUR (SECS_PER_HOUR*1000)
class a1time : public QDateTime
{
@ -39,13 +46,14 @@ class a1time : public QDateTime
QString toPlain(const QString &fmt = QString()) const;
QString toPlainUTC() const;
QString toSortable() const;
QString toISO8601() const;
QString toFancy() const;
QString isoLocalDate() const;
ASN1_TIME *get();
ASN1_TIME *get_utc();
static QDateTime now(int delta = 0);
QByteArray i2d();
void d2i(QByteArray &ba);
qint64 age() const;
};
#endif

View File

@ -22,6 +22,17 @@
QHash<quint64, pki_base*> db_base::lookup;
void db_base::restart_timer()
{
killTimer(secondsTimer);
killTimer(minutesTimer);
killTimer(hoursTimer);
secondsTimer = startTimer(1000);
minutesTimer = startTimer(MSECS_PER_MINUTE);
hoursTimer = startTimer(MSECS_PER_HOUR);
}
db_base::db_base(MainWindow *mw)
:QAbstractItemModel(NULL)
{
@ -31,6 +42,7 @@ db_base::db_base(MainWindow *mw)
colResizing = 0;
currentIdx = QModelIndex();
class_name = "base";
restart_timer();
}
db_base::~db_base()
@ -124,6 +136,7 @@ void db_base::loadContainer()
} else {
allHeaders.fromData(view);
}
restart_timer();
emit columnsContentChanged();
}
@ -221,6 +234,7 @@ void db_base::insertPKI(pki_base *pki)
lookup[pki->getSqlItemId().toULongLong()] = pki;
inToCont(pki);
TransCommit();
restart_timer();
emit columnsContentChanged();
}
@ -435,7 +449,7 @@ QVariant db_base::data(const QModelIndex &index, int role) const
switch (role) {
case Qt::EditRole:
case Qt::DisplayRole:
if (hd->id == HD_internal_name || item->isVisible() == 1)
if (hd->id==HD_internal_name || item->isVisible()==1)
return item->column_data(hd);
break;
case Qt::DecorationRole:
@ -448,6 +462,10 @@ QVariant db_base::data(const QModelIndex &index, int role) const
return item->bg_color(hd);
case Qt::UserRole:
return item->isVisible();
case Qt::ToolTipRole:
if (hd->id==HD_internal_name || item->isVisible()==1)
return item->column_tooltip(hd);
break;
}
return QVariant();
}
@ -538,6 +556,41 @@ void db_base::updateItem(pki_base *pki, QString name, QString comment)
j = index(i.row(), allHeaders.size(), i.parent());
emit dataChanged(i, j);
emit pkiChanged(pki);
restart_timer();
}
void db_base::timerEvent(QTimerEvent *event)
{
int youngest = SECS_PER_DAY;
int id = event->timerId();
int idx = allHeaders.column(HD_creation);
FOR_ALL_pki(pki, pki_base) {
int age = pki->getInsertionDate().age();
bool do_emit = false;
if (age < youngest)
youngest = age;
if (id == secondsTimer &&
(age < SECS_PER_MINUTE *2 || age % SECS_PER_MINUTE < 2))
do_emit = true;
if (id == minutesTimer && (age % SECS_PER_HOUR < 60))
do_emit = true;
if (id == hoursTimer && (age % SECS_PER_DAY < SECS_PER_HOUR))
do_emit = true;
if (do_emit) {
QModelIndex i = createIndex(pki->row(), idx, pki);
emit dataChanged(i, i);
}
}
if (secondsTimer && youngest > SECS_PER_HOUR *2) {
killTimer(secondsTimer);
secondsTimer = 0;
}
if (minutesTimer && youngest > SECS_PER_DAY *2) {
killTimer(minutesTimer);
minutesTimer = 0;
}
}
void db_base::editComment(const QModelIndex &index)

View File

@ -39,6 +39,7 @@ class db_base: public QAbstractItemModel
protected:
static QHash<quint64, pki_base*> lookup;
QModelIndex currentIdx;
int secondsTimer, minutesTimer, hoursTimer;
void _writePKI(pki_base *pki, bool overwrite);
void _removePKI(pki_base *pki );
void removeItem(QString k);
@ -59,6 +60,8 @@ class db_base: public QAbstractItemModel
bool isValidCol(int col) const;
static XSqlQuery sqlSELECTpki(QString query,
QList<QVariant> values = QList<QVariant>());
void timerEvent(QTimerEvent * event);
void restart_timer();
public:
template <class T> static T *lookupPki(quint64 i)

View File

@ -250,5 +250,12 @@ class dbheaderList: public QList<dbheader*>
}
}
}
int column(int type) // HD_...
{
for (int i=0; i<count(); i++)
if (at(i)->id == type)
return i;
return -1;
}
};
#endif

View File

@ -285,7 +285,7 @@ QVariant pki_base::column_data(const dbheader *hd) const
case HD_internal_name:
return QVariant(getIntName());
case HD_creation:
return QVariant(insertion_date.toSortable());
return QVariant(insertion_date.toFancy());
case HD_comment:
return QVariant(comment.section('\n', 0, 0));
case HD_source:
@ -302,6 +302,17 @@ QVariant pki_base::getIcon(const dbheader *hd) const
return QVariant();
}
QVariant pki_base::column_tooltip(const dbheader *hd) const
{
switch (hd->id) {
case HD_creation:
return QVariant(insertion_date.toPretty());
case HD_comment:
return QVariant(comment);
}
return QVariant();
}
bool pki_base::compare(const pki_base *ref) const
{
bool ret;

View File

@ -152,6 +152,7 @@ class pki_base : public QObject
int row() const;
virtual QVariant column_data(const dbheader *hd) const;
virtual QVariant getIcon(const dbheader *hd) const;
virtual QVariant column_tooltip(const dbheader *hd) const;
virtual bool visible() const;
int isVisible();
bool childVisible() const;

View File

@ -404,6 +404,17 @@ QVariant pki_crl::column_data(const dbheader *hd) const
return pki_x509name::column_data(hd);
}
QVariant pki_crl::column_tooltip(const dbheader *hd) const
{
switch (hd->id) {
case HD_crl_lastUpdate:
return QVariant(getLastUpdate().toPretty());
case HD_crl_nextUpdate:
return QVariant(getNextUpdate().toPretty());
}
return pki_x509name::column_tooltip(hd);
}
QVariant pki_crl::getIcon(const dbheader *hd) const
{
return hd->id == HD_internal_name ? QVariant(*icon) : QVariant();

View File

@ -77,6 +77,7 @@ class pki_crl: public pki_x509name
a1int getCrlNumber() const;
BIO *pem(BIO *, int);
bool visible() const;
QVariant column_tooltip(const dbheader *hd) const;
QSqlError insertSqlData();
QSqlError deleteSqlData();
void restoreSql(const QSqlRecord &rec);

View File

@ -939,8 +939,7 @@ QVariant pki_x509::column_data(const dbheader *hd) const
case HD_cert_crl_expire:
if (canSign() && !crlExpire.isUndefined())
return QVariant(crlExpire.toSortable());
else
return QVariant();
break;
case HD_cert_md5fp:
return QVariant(fingerprint(EVP_md5()));
case HD_cert_sha1fp:
@ -958,12 +957,30 @@ QVariant pki_x509::column_data(const dbheader *hd) const
else
return QVariant(tr("Yes"));
}
return QVariant("");
break;
}
}
return pki_x509super::column_data(hd);
}
QVariant pki_x509::column_tooltip(const dbheader *hd) const
{
switch (hd->id) {
case HD_cert_notBefore:
return QVariant(getNotBefore().toPretty());
case HD_cert_notAfter:
return QVariant(getNotAfter().toPretty());
case HD_cert_revocation:
return QVariant(isRevoked() ?
revocation.getDate().toPretty() : "");
case HD_cert_crl_expire:
if (canSign() && !crlExpire.isUndefined())
return QVariant(crlExpire.toPretty());
break;
}
return pki_x509super::column_tooltip(hd);
}
QStringList pki_x509::icsVEVENT() const
{
return pki_base::icsVEVENT(getNotAfter(),

View File

@ -156,6 +156,7 @@ class pki_x509 : public pki_x509super
void setRevocations(const x509revList &rl);
x509revList getRevList() const;
bool compareNameAndKey(pki_x509 *other);
QVariant column_tooltip(const dbheader *hd) const;
void setCrlExpire(a1time a)
{
crlExpire = a;

View File

@ -15,7 +15,10 @@ bool XcaProxyModel::lessThan(const QModelIndex &left,
if (!db)
return QSortFilterProxyModel::lessThan(left, right);
if (left.column() < 0 || right.column() < 0) {
dbheaderList headers = db->getAllHeaders();
if (left.column() < 0 || left.column() >= headers.size() ||
right.column() < 0 || right.column() >= headers.size())
{
qDebug("BAD COLUMN: %d %d\n", left.column(), right.column());
return true;
}
@ -33,6 +36,15 @@ bool XcaProxyModel::lessThan(const QModelIndex &left,
else
return l < r;
}
if (headers[left.column()]->id == HD_creation &&
headers[right.column()]->id == HD_creation)
{
pki_base *l = static_cast<pki_base*>(left.internalPointer());
pki_base *r = static_cast<pki_base*>(right.internalPointer());
if (l && r) {
return l->getInsertionDate() < r->getInsertionDate();
}
}
return QSortFilterProxyModel::lessThan(left, right);
}