okular/ui/signaturemodel.cpp
Chinmoy Ranjan Pradhan a234a902dc Implement digital signature support for PDF
This is a squash of the original branch

It also contains fixes/rework from Albert Astals Cid

If you're interested in its history have a look at the
gsoc2018_digitalsignature branch

The poppler dependency situation is:
 * With 0.51 you get most signature information
 * With 0.68 you also get signature location/reason information
 * With 0.73 you also get signature certificate information
2019-01-10 23:13:54 +01:00

276 lines
8.9 KiB
C++

/***************************************************************************
* Copyright (C) 2018 by Chinmoy Ranjan Pradhan <chinmoyrp65@gmail.com *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
***************************************************************************/
#include "signaturemodel.h"
#include "signatureguiutils.h"
#include <KLocalizedString>
#include <QIcon>
#include <QVector>
#include <QPointer>
#include "core/document.h"
#include "core/observer.h"
#include "core/page.h"
#include "core/form.h"
#include "core/signatureutils.h"
struct SignatureItem
{
enum DataType
{
Root,
RevisionInfo,
ValidityStatus,
SigningTime,
Reason,
FieldInfo
};
SignatureItem();
SignatureItem( SignatureItem *parent, const Okular::FormFieldSignature *form, DataType type, int page );
~SignatureItem();
SignatureItem(const SignatureItem &) = delete;
SignatureItem &operator=(const SignatureItem &) = delete;
QVector<SignatureItem *> children;
SignatureItem *parent;
const Okular::FormFieldSignature *form;
QString displayString;
DataType type;
int page;
};
SignatureItem::SignatureItem()
: parent( nullptr ), form( nullptr ), type( Root ), page( -1 )
{
}
SignatureItem::SignatureItem( SignatureItem *_parent, const Okular::FormFieldSignature *_form , DataType _type, int _page )
: parent( _parent ), form( _form ), type( _type ), page( _page )
{
Q_ASSERT( parent );
parent->children.append( this );
}
SignatureItem::~SignatureItem()
{
qDeleteAll( children );
}
class SignatureModelPrivate : public Okular::DocumentObserver
{
public:
SignatureModelPrivate( SignatureModel *qq );
~SignatureModelPrivate() override;
void notifySetup( const QVector<Okular::Page *> &pages, int setupFlags ) override;
QModelIndex indexForItem( SignatureItem *item ) const;
SignatureModel *q;
SignatureItem *root;
QPointer<Okular::Document> document;
};
SignatureModelPrivate::SignatureModelPrivate( SignatureModel *qq )
: q( qq ), root( new SignatureItem )
{
}
SignatureModelPrivate::~SignatureModelPrivate()
{
delete root;
}
static void updateFormFieldSignaturePointer( SignatureItem *item, const QVector<Okular::Page*> &pages )
{
if ( item->form )
{
foreach ( Okular::FormField *f, pages[item->page]->formFields() )
{
if ( item->form->id() == f->id() )
{
item->form = static_cast<Okular::FormFieldSignature*>( f );
break;
}
}
if ( !item->form )
qWarning() << "Lost signature form field, something went wrong";
}
foreach ( SignatureItem *child, item->children )
updateFormFieldSignaturePointer( child, pages );
}
void SignatureModelPrivate::notifySetup( const QVector<Okular::Page*> &pages, int setupFlags )
{
if ( !( setupFlags & Okular::DocumentObserver::DocumentChanged ) )
{
if ( setupFlags & Okular::DocumentObserver::UrlChanged )
{
updateFormFieldSignaturePointer( root, pages );
}
return;
}
q->beginResetModel();
qDeleteAll( root->children );
root->children.clear();
foreach ( auto page, pages )
{
const int currentPage = page->number();
// get form fields page by page so that page number and index of the form can be determined.
const QVector<const Okular::FormFieldSignature*> signatureFormFields = SignatureGuiUtils::getSignatureFormFields( document, false, currentPage );
if ( signatureFormFields.isEmpty() )
continue;
for ( int i = 0; i < signatureFormFields.count(); i++ )
{
const Okular::FormFieldSignature *sf = signatureFormFields[i];
const Okular::SignatureInfo &info = sf->signatureInfo();
// based on whether or not signature form is a nullptr it is decided if clicking on an item should change the viewport.
auto *parentItem = new SignatureItem( root, sf, SignatureItem::RevisionInfo, currentPage );
parentItem->displayString = i18n( "Rev. %1: Signed By %2", i+1, info.signerName() );
auto childItem1 = new SignatureItem( parentItem, nullptr, SignatureItem::ValidityStatus, currentPage );
childItem1->displayString = SignatureGuiUtils::getReadableSignatureStatus( info.signatureStatus() );
auto childItem2 = new SignatureItem( parentItem, nullptr, SignatureItem::SigningTime, currentPage );
childItem2->displayString = i18n("Signing Time: %1", info.signingTime().toString( Qt::DefaultLocaleLongDate ) );
auto childItem3 = new SignatureItem( parentItem, nullptr, SignatureItem::Reason, currentPage );
childItem3->displayString = i18n("Reason: %1", !info.reason().isEmpty() ? info.reason() : i18n("Not Available") );
auto childItem4 = new SignatureItem( parentItem, sf, SignatureItem::FieldInfo, currentPage );
childItem4->displayString = i18n("Field: %1 on page %2", sf->name(), currentPage+1 );
}
}
q->endResetModel();
}
QModelIndex SignatureModelPrivate::indexForItem( SignatureItem *item ) const
{
if ( item->parent )
{
const int index = item->parent->children.indexOf( item );
if ( index >= 0 && index < item->parent->children.count() )
return q->createIndex( index, 0, item );
}
return QModelIndex();
}
SignatureModel::SignatureModel( Okular::Document *doc, QObject *parent )
: QAbstractItemModel( parent ), d_ptr( new SignatureModelPrivate( this ) )
{
Q_D( SignatureModel );
d->document = doc;
d->document->addObserver( d );
}
SignatureModel::~SignatureModel()
{
Q_D( SignatureModel );
d->document->removeObserver( d );
}
int SignatureModel::columnCount( const QModelIndex & ) const
{
return 1;
}
QVariant SignatureModel::data( const QModelIndex &index, int role ) const
{
Q_D( const SignatureModel );
if ( !index.isValid() )
return QVariant();
const SignatureItem *item = static_cast<SignatureItem *>( index.internalPointer() );
if ( item == d->root )
return QVariant();
switch ( role )
{
case Qt::DisplayRole:
case Qt::ToolTipRole:
return item->displayString;
case Qt::DecorationRole:
if ( item->type == SignatureItem::RevisionInfo )
{
const Okular::SignatureInfo::SignatureStatus signatureStatus = item->form->signatureInfo().signatureStatus();
switch ( signatureStatus )
{
case Okular::SignatureInfo::SignatureValid:
return QIcon::fromTheme( QStringLiteral("dialog-ok") );
case Okular::SignatureInfo::SignatureInvalid:
return QIcon::fromTheme( QStringLiteral("dialog-close") );
case Okular::SignatureInfo::SignatureDigestMismatch:
return QIcon::fromTheme( QStringLiteral("dialog-warning") );
default:
return QIcon::fromTheme( QStringLiteral("dialog-question") );
}
}
return QIcon();
case FormRole:
return QVariant::fromValue<const Okular::FormFieldSignature *>(item->form);
case PageRole:
return item->page;
}
return QVariant();
}
bool SignatureModel::hasChildren( const QModelIndex &parent ) const
{
if ( !parent.isValid() )
return true;
const SignatureItem *item = static_cast<SignatureItem *>( parent.internalPointer() );
return !item->children.isEmpty();
}
QModelIndex SignatureModel::index( int row, int column, const QModelIndex &parent ) const
{
Q_D( const SignatureModel );
if ( row < 0 || column != 0 )
return QModelIndex();
const SignatureItem *item = parent.isValid() ? static_cast<SignatureItem *>( parent.internalPointer() ) : d->root;
if ( row < item->children.count() )
return createIndex( row, column, item->children.at( row ) );
return QModelIndex();
}
QModelIndex SignatureModel::parent( const QModelIndex &index ) const
{
Q_D( const SignatureModel );
if ( !index.isValid() )
return QModelIndex();
const SignatureItem *item = static_cast<SignatureItem *>( index.internalPointer() );
return d->indexForItem( item->parent );
}
int SignatureModel::rowCount( const QModelIndex &parent ) const
{
Q_D( const SignatureModel );
const SignatureItem *item = parent.isValid() ? static_cast<SignatureItem*>( parent.internalPointer() ) : d->root;
return item->children.count();
}
#include "moc_signaturemodel.cpp"