diff --git a/lib/asn1time.cpp b/lib/asn1time.cpp index 7d65b2d4..20d38143 100644 --- a/lib/asn1time.cpp +++ b/lib/asn1time.cpp @@ -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); diff --git a/lib/asn1time.h b/lib/asn1time.h index 0fe9dd73..e7d449e4 100644 --- a/lib/asn1time.h +++ b/lib/asn1time.h @@ -12,7 +12,14 @@ #include #include -#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 diff --git a/lib/db_base.cpp b/lib/db_base.cpp index a0562e0e..5352c621 100644 --- a/lib/db_base.cpp +++ b/lib/db_base.cpp @@ -22,6 +22,17 @@ QHash 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) diff --git a/lib/db_base.h b/lib/db_base.h index 941e0cf7..92133d97 100644 --- a/lib/db_base.h +++ b/lib/db_base.h @@ -39,6 +39,7 @@ class db_base: public QAbstractItemModel protected: static QHash 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 values = QList()); + void timerEvent(QTimerEvent * event); + void restart_timer(); public: template static T *lookupPki(quint64 i) diff --git a/lib/headerlist.h b/lib/headerlist.h index 97848618..b410ee1e 100644 --- a/lib/headerlist.h +++ b/lib/headerlist.h @@ -250,5 +250,12 @@ class dbheaderList: public QList } } } + int column(int type) // HD_... + { + for (int i=0; iid == type) + return i; + return -1; + } }; #endif diff --git a/lib/pki_base.cpp b/lib/pki_base.cpp index b22ace01..cb6c883a 100644 --- a/lib/pki_base.cpp +++ b/lib/pki_base.cpp @@ -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; diff --git a/lib/pki_base.h b/lib/pki_base.h index 3b969641..f3d7b42e 100644 --- a/lib/pki_base.h +++ b/lib/pki_base.h @@ -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; diff --git a/lib/pki_crl.cpp b/lib/pki_crl.cpp index d08b63a1..f61409b7 100644 --- a/lib/pki_crl.cpp +++ b/lib/pki_crl.cpp @@ -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(); diff --git a/lib/pki_crl.h b/lib/pki_crl.h index a765bf88..6434d6e3 100644 --- a/lib/pki_crl.h +++ b/lib/pki_crl.h @@ -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); diff --git a/lib/pki_x509.cpp b/lib/pki_x509.cpp index 5b75bbe4..2ec32a53 100644 --- a/lib/pki_x509.cpp +++ b/lib/pki_x509.cpp @@ -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(), diff --git a/lib/pki_x509.h b/lib/pki_x509.h index 79d743b8..ee7eb411 100644 --- a/lib/pki_x509.h +++ b/lib/pki_x509.h @@ -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; diff --git a/widgets/XcaProxyModel.cpp b/widgets/XcaProxyModel.cpp index c0013852..e98fc170 100644 --- a/widgets/XcaProxyModel.cpp +++ b/widgets/XcaProxyModel.cpp @@ -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(left.internalPointer()); + pki_base *r = static_cast(right.internalPointer()); + if (l && r) { + return l->getInsertionDate() < r->getInsertionDate(); + } + } return QSortFilterProxyModel::lessThan(left, right); }