2020-01-18 11:38:54 +01:00
// Copyright (C) 2019-2020 Jakub Melka
2019-11-28 18:20:32 +01:00
//
2020-12-20 19:03:58 +01:00
// This file is part of Pdf4Qt.
2019-11-28 18:20:32 +01:00
//
2020-12-20 19:03:58 +01:00
// Pdf4Qt is free software: you can redistribute it and/or modify
2019-11-28 18:20:32 +01:00
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
2020-12-20 19:03:58 +01:00
// Pdf4Qt is distributed in the hope that it will be useful,
2019-11-28 18:20:32 +01:00
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public License
2020-12-20 19:03:58 +01:00
// along with Pdf4Qt. If not, see <https://www.gnu.org/licenses/>.
2019-11-28 18:20:32 +01:00
# include "pdfsidebarwidget.h"
# include "ui_pdfsidebarwidget.h"
2020-06-27 17:28:03 +02:00
# include "pdfviewersettings.h"
2019-12-07 17:59:03 +01:00
# include "pdfwidgetutils.h"
2020-02-18 20:21:18 +01:00
# include "pdftexttospeech.h"
2019-12-07 17:59:03 +01:00
2019-11-28 18:20:32 +01:00
# include "pdfdocument.h"
# include "pdfitemmodels.h"
2019-12-03 19:24:43 +01:00
# include "pdfexception.h"
2020-06-20 18:20:57 +02:00
# include "pdfsignaturehandler.h"
2019-12-08 19:20:36 +01:00
# include "pdfdrawspacecontroller.h"
2019-12-03 19:24:43 +01:00
# include <QMenu>
# include <QAction>
# include <QFileDialog>
# include <QStandardPaths>
# include <QMessageBox>
2019-12-04 19:18:40 +01:00
# include <QPainter>
2019-11-28 18:20:32 +01:00
namespace pdfviewer
{
2019-12-04 19:18:40 +01:00
constexpr const char * STYLESHEET =
" QPushButton { background-color: #404040; color: #FFFFFF; } "
" QPushButton:disabled { background-color: #404040; color: #000000; } "
" QPushButton:checked { background-color: #808080; color: #FFFFFF; } "
2019-12-07 17:59:03 +01:00
" QWidget#thumbnailsToolbarWidget { background-color: #F0F0F0 } "
2020-02-18 20:21:18 +01:00
" QWidget#speechPage { background-color: #F0F0F0 } "
2019-12-04 19:18:40 +01:00
" QWidget#PDFSidebarWidget { background-color: #404040; background: green;} " ;
2020-06-27 17:28:03 +02:00
PDFSidebarWidget : : PDFSidebarWidget ( pdf : : PDFDrawWidgetProxy * proxy ,
PDFTextToSpeech * textToSpeech ,
pdf : : PDFCertificateStore * certificateStore ,
PDFViewerSettings * settings ,
QWidget * parent ) :
2019-11-28 18:20:32 +01:00
QWidget ( parent ) ,
ui ( new Ui : : PDFSidebarWidget ) ,
2019-12-08 19:20:36 +01:00
m_proxy ( proxy ) ,
2020-02-18 20:21:18 +01:00
m_textToSpeech ( textToSpeech ) ,
2020-06-27 17:28:03 +02:00
m_certificateStore ( certificateStore ) ,
m_settings ( settings ) ,
2019-11-28 18:20:32 +01:00
m_outlineTreeModel ( nullptr ) ,
2019-12-07 17:59:03 +01:00
m_thumbnailsModel ( nullptr ) ,
2019-11-28 18:20:32 +01:00
m_optionalContentTreeModel ( nullptr ) ,
m_document ( nullptr ) ,
2019-12-01 18:10:11 +01:00
m_optionalContentActivity ( nullptr ) ,
m_attachmentsTreeModel ( nullptr )
2019-11-28 18:20:32 +01:00
{
ui - > setupUi ( this ) ;
2019-12-04 19:18:40 +01:00
setStyleSheet ( STYLESHEET ) ;
2019-11-28 18:20:32 +01:00
// Outline
2019-11-29 19:10:29 +01:00
QIcon bookmarkIcon ( " :/resources/bookmark.svg " ) ;
m_outlineTreeModel = new pdf : : PDFOutlineTreeItemModel ( qMove ( bookmarkIcon ) , this ) ;
2019-11-28 18:20:32 +01:00
ui - > bookmarksTreeView - > setModel ( m_outlineTreeModel ) ;
ui - > bookmarksTreeView - > header ( ) - > hide ( ) ;
2019-11-29 19:10:29 +01:00
connect ( ui - > bookmarksTreeView , & QTreeView : : clicked , this , & PDFSidebarWidget : : onOutlineItemClicked ) ;
2019-11-28 18:20:32 +01:00
2019-12-07 17:59:03 +01:00
// Thumbnails
m_thumbnailsModel = new pdf : : PDFThumbnailsItemModel ( proxy , this ) ;
int thumbnailsMargin = ui - > thumbnailsListView - > style ( ) - > pixelMetric ( QStyle : : PM_FocusFrameHMargin , nullptr , ui - > thumbnailsListView ) + 1 ;
int thumbnailsFontSize = QFontMetrics ( ui - > thumbnailsListView - > font ( ) ) . lineSpacing ( ) ;
m_thumbnailsModel - > setExtraItemSizeHint ( 2 * thumbnailsMargin , thumbnailsMargin + thumbnailsFontSize ) ;
ui - > thumbnailsListView - > setModel ( m_thumbnailsModel ) ;
connect ( ui - > thumbnailsSizeSlider , & QSlider : : valueChanged , this , & PDFSidebarWidget : : onThumbnailsSizeChanged ) ;
2019-12-08 19:20:36 +01:00
connect ( ui - > thumbnailsListView , & QListView : : clicked , this , & PDFSidebarWidget : : onThumbnailClicked ) ;
2019-12-07 17:59:03 +01:00
onThumbnailsSizeChanged ( ui - > thumbnailsSizeSlider - > value ( ) ) ;
2019-11-28 18:20:32 +01:00
// Optional content
ui - > optionalContentTreeView - > header ( ) - > hide ( ) ;
m_optionalContentTreeModel = new pdf : : PDFOptionalContentTreeItemModel ( this ) ;
ui - > optionalContentTreeView - > setModel ( m_optionalContentTreeModel ) ;
2019-12-01 18:10:11 +01:00
// Attachments
ui - > attachmentsTreeView - > header ( ) - > hide ( ) ;
m_attachmentsTreeModel = new pdf : : PDFAttachmentsTreeItemModel ( this ) ;
ui - > attachmentsTreeView - > setModel ( m_attachmentsTreeModel ) ;
ui - > attachmentsTreeView - > setSelectionMode ( QAbstractItemView : : SingleSelection ) ;
2019-12-03 19:24:43 +01:00
ui - > attachmentsTreeView - > setSelectionBehavior ( QAbstractItemView : : SelectItems ) ;
ui - > attachmentsTreeView - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
connect ( ui - > attachmentsTreeView , & QTreeView : : customContextMenuRequested , this , & PDFSidebarWidget : : onAttachmentCustomContextMenuRequested ) ;
2019-12-01 18:10:11 +01:00
2019-11-28 18:20:32 +01:00
m_pageInfo [ Invalid ] = { nullptr , ui - > emptyPage } ;
m_pageInfo [ OptionalContent ] = { ui - > optionalContentButton , ui - > optionalContentPage } ;
m_pageInfo [ Bookmarks ] = { ui - > bookmarksButton , ui - > bookmarksPage } ;
m_pageInfo [ Thumbnails ] = { ui - > thumbnailsButton , ui - > thumbnailsPage } ;
2019-12-01 18:10:11 +01:00
m_pageInfo [ Attachments ] = { ui - > attachmentsButton , ui - > attachmentsPage } ;
2020-02-18 20:21:18 +01:00
m_pageInfo [ Speech ] = { ui - > speechButton , ui - > speechPage } ;
2020-06-20 18:20:57 +02:00
m_pageInfo [ Signatures ] = { ui - > signaturesButton , ui - > signaturesPage } ;
2019-11-28 18:20:32 +01:00
2019-12-07 17:59:03 +01:00
for ( const auto & pageInfo : m_pageInfo )
{
if ( pageInfo . second . button )
{
connect ( pageInfo . second . button , & QPushButton : : clicked , this , & PDFSidebarWidget : : onPageButtonClicked ) ;
}
}
2020-02-18 20:21:18 +01:00
m_textToSpeech - > initializeUI ( ui - > speechLocaleComboBox , ui - > speechVoiceComboBox ,
ui - > speechRateEdit , ui - > speechPitchEdit , ui - > speechVolumeEdit ,
2020-02-20 19:25:32 +01:00
ui - > speechPlayButton , ui - > speechPauseButton , ui - > speechStopButton , ui - > speechSynchronizeButton ,
ui - > speechRateValueLabel , ui - > speechPitchValueLabel , ui - > speechVolumeValueLabel ,
ui - > speechActualTextEdit ) ;
2020-02-18 20:21:18 +01:00
2020-06-27 17:28:03 +02:00
ui - > signatureTreeWidget - > setContextMenuPolicy ( Qt : : CustomContextMenu ) ;
connect ( ui - > signatureTreeWidget , & QTreeWidget : : customContextMenuRequested , this , & PDFSidebarWidget : : onSignatureCustomContextMenuRequested ) ;
2019-11-28 18:20:32 +01:00
selectPage ( Invalid ) ;
updateButtons ( ) ;
}
PDFSidebarWidget : : ~ PDFSidebarWidget ( )
{
delete ui ;
}
2020-06-20 18:20:57 +02:00
void PDFSidebarWidget : : setDocument ( const pdf : : PDFModifiedDocument & document , const std : : vector < pdf : : PDFSignatureVerificationResult > & signatures )
2019-11-28 18:20:32 +01:00
{
m_document = document ;
2020-04-25 14:21:06 +02:00
m_optionalContentActivity = document . getOptionalContentActivity ( ) ;
2020-07-06 16:31:41 +02:00
m_signatures = signatures ;
2019-11-28 18:20:32 +01:00
// Update outline
m_outlineTreeModel - > setDocument ( document ) ;
2019-12-07 17:59:03 +01:00
// Thumbnails
m_thumbnailsModel - > setDocument ( document ) ;
2019-11-28 18:20:32 +01:00
// Update optional content
m_optionalContentTreeModel - > setDocument ( document ) ;
m_optionalContentTreeModel - > setActivity ( m_optionalContentActivity ) ;
ui - > optionalContentTreeView - > expandAll ( ) ;
2019-12-01 18:10:11 +01:00
// Update attachments
m_attachmentsTreeModel - > setDocument ( document ) ;
ui - > attachmentsTreeView - > expandAll ( ) ;
ui - > attachmentsTreeView - > resizeColumnToContents ( 0 ) ;
2019-11-28 18:20:32 +01:00
Page preferred = Invalid ;
if ( m_document )
{
2019-11-29 19:10:29 +01:00
const pdf : : PageMode pageMode = m_document - > getCatalog ( ) - > getPageMode ( ) ;
2019-11-28 18:20:32 +01:00
switch ( pageMode )
{
2019-11-29 19:10:29 +01:00
case pdf : : PageMode : : UseOutlines :
2019-11-28 18:20:32 +01:00
preferred = Bookmarks ;
break ;
2019-11-29 19:10:29 +01:00
case pdf : : PageMode : : UseThumbnails :
2019-11-28 18:20:32 +01:00
preferred = Thumbnails ;
break ;
2019-11-29 19:10:29 +01:00
case pdf : : PageMode : : UseOptionalContent :
2019-11-28 18:20:32 +01:00
preferred = OptionalContent ;
break ;
2019-12-01 18:10:11 +01:00
case pdf : : PageMode : : UseAttachments :
preferred = Attachments ;
break ;
2019-12-07 17:59:03 +01:00
case pdf : : PageMode : : Fullscreen :
{
pdf : : PDFViewerPreferences : : NonFullScreenPageMode nonFullscreenPageMode = m_document - > getCatalog ( ) - > getViewerPreferences ( ) - > getNonFullScreenPageMode ( ) ;
switch ( nonFullscreenPageMode )
{
case pdf : : PDFViewerPreferences : : NonFullScreenPageMode : : UseOutline :
preferred = Bookmarks ;
break ;
case pdf : : PDFViewerPreferences : : NonFullScreenPageMode : : UseThumbnails :
preferred = Thumbnails ;
break ;
case pdf : : PDFViewerPreferences : : NonFullScreenPageMode : : UseOptionalContent :
preferred = OptionalContent ;
break ;
default :
break ;
}
break ;
}
2019-11-28 18:20:32 +01:00
default :
break ;
}
}
// Update GUI
updateGUI ( preferred ) ;
updateButtons ( ) ;
2020-06-20 18:20:57 +02:00
updateSignatures ( signatures ) ;
2019-11-28 18:20:32 +01:00
}
bool PDFSidebarWidget : : isEmpty ( ) const
{
for ( int i = _BEGIN ; i < _END ; + + i )
{
if ( ! isEmpty ( static_cast < Page > ( i ) ) )
{
return false ;
}
}
return true ;
}
bool PDFSidebarWidget : : isEmpty ( Page page ) const
{
switch ( page )
{
case Invalid :
return true ;
case Bookmarks :
return m_outlineTreeModel - > isEmpty ( ) ;
case Thumbnails :
2019-12-07 17:59:03 +01:00
return m_thumbnailsModel - > isEmpty ( ) ;
2019-11-28 18:20:32 +01:00
2019-12-01 18:10:11 +01:00
case OptionalContent :
return m_optionalContentTreeModel - > isEmpty ( ) ;
case Attachments :
return m_attachmentsTreeModel - > isEmpty ( ) ;
2020-02-18 20:21:18 +01:00
case Speech :
return ! m_textToSpeech - > isValid ( ) ;
2020-06-20 18:20:57 +02:00
case Signatures :
2020-07-06 16:31:41 +02:00
return m_signatures . empty ( ) ;
2020-06-20 18:20:57 +02:00
2019-11-28 18:20:32 +01:00
default :
Q_ASSERT ( false ) ;
break ;
}
return true ;
}
void PDFSidebarWidget : : selectPage ( Page page )
{
// Switch state of the buttons and select the page
for ( const auto & pageInfo : m_pageInfo )
{
if ( pageInfo . second . button )
{
pageInfo . second . button - > setChecked ( pageInfo . first = = page ) ;
}
if ( pageInfo . first = = page )
{
ui - > stackedWidget - > setCurrentWidget ( pageInfo . second . page ) ;
}
}
}
std : : vector < PDFSidebarWidget : : Page > PDFSidebarWidget : : getValidPages ( ) const
{
std : : vector < PDFSidebarWidget : : Page > result ;
result . reserve ( _END - _BEGIN + 1 ) ;
for ( int i = _BEGIN ; i < _END ; + + i )
{
if ( ! isEmpty ( static_cast < Page > ( i ) ) )
{
result . push_back ( static_cast < Page > ( i ) ) ;
}
}
return result ;
}
2019-12-08 19:20:36 +01:00
void PDFSidebarWidget : : setCurrentPages ( const std : : vector < pdf : : PDFInteger > & currentPages )
{
if ( ! currentPages . empty ( ) & & ui - > synchronizeThumbnailsButton - > isChecked ( ) )
{
QModelIndex index = m_thumbnailsModel - > index ( currentPages . front ( ) , 0 , QModelIndex ( ) ) ;
if ( index . isValid ( ) )
{
ui - > thumbnailsListView - > scrollTo ( index , QListView : : EnsureVisible ) ;
// Try to examine, if we have to switch the current index
QModelIndex currentIndex = ui - > thumbnailsListView - > currentIndex ( ) ;
if ( currentIndex . isValid ( ) )
{
const pdf : : PDFInteger currentPageIndex = m_thumbnailsModel - > getPageIndex ( currentIndex ) ;
Q_ASSERT ( std : : is_sorted ( currentPages . cbegin ( ) , currentPages . cend ( ) ) ) ;
if ( std : : binary_search ( currentPages . cbegin ( ) , currentPages . cend ( ) , currentPageIndex ) )
{
return ;
}
}
ui - > thumbnailsListView - > setCurrentIndex ( index ) ;
}
}
}
2019-11-28 18:20:32 +01:00
void PDFSidebarWidget : : updateGUI ( Page preferredPage )
{
if ( preferredPage ! = Invalid & & ! isEmpty ( preferredPage ) )
{
selectPage ( preferredPage ) ;
}
else
{
// Select first nonempty page
std : : vector < Page > validPages = getValidPages ( ) ;
if ( ! validPages . empty ( ) )
{
selectPage ( validPages . front ( ) ) ;
}
else
{
selectPage ( Invalid ) ;
}
}
}
void PDFSidebarWidget : : updateButtons ( )
{
for ( const auto & pageInfo : m_pageInfo )
{
if ( pageInfo . second . button )
{
pageInfo . second . button - > setEnabled ( ! isEmpty ( pageInfo . first ) ) ;
}
}
}
2020-06-20 18:20:57 +02:00
void PDFSidebarWidget : : updateSignatures ( const std : : vector < pdf : : PDFSignatureVerificationResult > & signatures )
{
ui - > signatureTreeWidget - > setUpdatesEnabled ( false ) ;
ui - > signatureTreeWidget - > clear ( ) ;
2020-06-27 17:28:03 +02:00
m_certificateInfos . clear ( ) ;
2020-06-20 18:20:57 +02:00
QIcon okIcon ( " :/resources/result-ok.svg " ) ;
QIcon errorIcon ( " :/resources/result-error.svg " ) ;
QIcon warningIcon ( " :/resources/result-warning.svg " ) ;
QIcon infoIcon ( " :/resources/result-information.svg " ) ;
2020-06-27 17:28:03 +02:00
if ( m_settings - > getSettings ( ) . m_signatureTreatWarningsAsErrors )
{
warningIcon = errorIcon ;
}
2020-06-20 18:20:57 +02:00
for ( const pdf : : PDFSignatureVerificationResult & signature : signatures )
{
const pdf : : PDFCertificateInfos & certificateInfos = signature . getCertificateInfos ( ) ;
const pdf : : PDFCertificateInfo * certificateInfo = ! certificateInfos . empty ( ) ? & certificateInfos . front ( ) : nullptr ;
2020-07-07 15:18:44 +02:00
QString templateString ;
switch ( signature . getType ( ) )
{
case pdf : : PDFSignature : : Type : : Sig :
2020-09-28 14:41:42 +02:00
templateString = tr ( " Signature - %1 " ) ;
2020-07-07 15:18:44 +02:00
break ;
case pdf : : PDFSignature : : Type : : DocTimeStamp :
2020-09-28 14:41:42 +02:00
templateString = tr ( " Timestamp - %1 " ) ;
2020-07-07 15:18:44 +02:00
break ;
2020-09-19 14:42:40 +02:00
case pdf : : PDFSignature : : Type : : Invalid :
continue ;
2020-07-07 15:18:44 +02:00
default :
Q_ASSERT ( false ) ;
break ;
}
QString text = templateString . arg ( certificateInfo ? certificateInfo - > getName ( pdf : : PDFCertificateInfo : : CommonName ) : tr ( " Unknown " ) ) ;
2020-06-20 18:20:57 +02:00
QTreeWidgetItem * rootItem = new QTreeWidgetItem ( QStringList ( text ) ) ;
if ( signature . hasError ( ) )
{
rootItem - > setIcon ( 0 , errorIcon ) ;
}
else if ( signature . hasWarning ( ) )
{
rootItem - > setIcon ( 0 , warningIcon ) ;
}
else
{
rootItem - > setIcon ( 0 , okIcon ) ;
}
if ( signature . isCertificateValid ( ) )
{
QTreeWidgetItem * certificateItem = new QTreeWidgetItem ( rootItem , QStringList ( tr ( " Certificate is valid. " ) ) ) ;
certificateItem - > setIcon ( 0 , okIcon ) ;
}
if ( signature . isSignatureValid ( ) )
{
QTreeWidgetItem * signatureItem = new QTreeWidgetItem ( rootItem , QStringList ( tr ( " Signature is valid. " ) ) ) ;
signatureItem - > setIcon ( 0 , okIcon ) ;
}
for ( const QString & error : signature . getErrors ( ) )
{
QTreeWidgetItem * item = new QTreeWidgetItem ( rootItem , QStringList ( error ) ) ;
item - > setIcon ( 0 , errorIcon ) ;
}
for ( const QString & error : signature . getWarnings ( ) )
{
QTreeWidgetItem * item = new QTreeWidgetItem ( rootItem , QStringList ( error ) ) ;
item - > setIcon ( 0 , warningIcon ) ;
}
2020-09-27 18:02:57 +02:00
QString hashAlgorithms = signature . getHashAlgorithms ( ) . join ( " , " ) ;
if ( ! hashAlgorithms . isEmpty ( ) )
{
2020-09-28 14:41:42 +02:00
QTreeWidgetItem * item = new QTreeWidgetItem ( rootItem , QStringList ( tr ( " Hash algorithm: %1 " ) . arg ( hashAlgorithms . toUpper ( ) ) ) ) ;
item - > setIcon ( 0 , infoIcon ) ;
}
QDateTime signingDate = signature . getSignatureDate ( ) ;
if ( signingDate . isValid ( ) )
{
QTreeWidgetItem * item = new QTreeWidgetItem ( rootItem , QStringList ( QString ( " Signing date/time: %2 " ) . arg ( signingDate . toString ( Qt : : DefaultLocaleShortDate ) ) ) ) ;
item - > setIcon ( 0 , infoIcon ) ;
}
QDateTime timestampDate = signature . getTimestampDate ( ) ;
if ( timestampDate . isValid ( ) )
{
QTreeWidgetItem * item = new QTreeWidgetItem ( rootItem , QStringList ( QString ( " Timestamp: %2 " ) . arg ( timestampDate . toString ( Qt : : DefaultLocaleShortDate ) ) ) ) ;
2020-09-27 18:02:57 +02:00
item - > setIcon ( 0 , infoIcon ) ;
}
2020-06-20 18:20:57 +02:00
if ( certificateInfo )
{
QTreeWidgetItem * certChainRoot = new QTreeWidgetItem ( rootItem , QStringList ( tr ( " Certificate validation chain " ) ) ) ;
certChainRoot - > setIcon ( 0 , infoIcon ) ;
for ( const pdf : : PDFCertificateInfo & currentCertificateInfo : certificateInfos )
{
QTreeWidgetItem * certRoot = new QTreeWidgetItem ( certChainRoot , QStringList ( currentCertificateInfo . getName ( pdf : : PDFCertificateInfo : : CommonName ) ) ) ;
certRoot - > setIcon ( 0 , infoIcon ) ;
2020-06-27 17:28:03 +02:00
pdf : : PDFCertificateInfo : : KeyUsageFlags keyUsageFlags = currentCertificateInfo . getKeyUsage ( ) ;
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageCertSign ) )
{
m_certificateInfos . push_back ( currentCertificateInfo ) ;
certRoot - > setData ( 0 , Qt : : UserRole , m_certificateInfos . size ( ) - 1 ) ;
}
2020-06-20 18:20:57 +02:00
auto addName = [ certRoot , & currentCertificateInfo , & infoIcon ] ( pdf : : PDFCertificateInfo : : NameEntry nameEntry , QString caption )
{
QString text = currentCertificateInfo . getName ( nameEntry ) ;
if ( ! text . isEmpty ( ) )
{
QTreeWidgetItem * item = new QTreeWidgetItem ( certRoot , QStringList ( QString ( " %1: %2 " ) . arg ( caption , text ) ) ) ;
item - > setIcon ( 0 , infoIcon ) ;
}
} ;
QString publicKeyMethod ;
switch ( currentCertificateInfo . getPublicKey ( ) )
{
case pdf : : PDFCertificateInfo : : KeyRSA :
publicKeyMethod = tr ( " Protected by RSA method, %1-bit key " ) . arg ( currentCertificateInfo . getKeySize ( ) ) ;
break ;
case pdf : : PDFCertificateInfo : : KeyDSA :
publicKeyMethod = tr ( " Protected by DSA method, %1-bit key " ) . arg ( currentCertificateInfo . getKeySize ( ) ) ;
break ;
case pdf : : PDFCertificateInfo : : KeyEC :
publicKeyMethod = tr ( " Protected by EC method, %1-bit key " ) . arg ( currentCertificateInfo . getKeySize ( ) ) ;
break ;
case pdf : : PDFCertificateInfo : : KeyDH :
publicKeyMethod = tr ( " Protected by DH method, %1-bit key " ) . arg ( currentCertificateInfo . getKeySize ( ) ) ;
break ;
case pdf : : PDFCertificateInfo : : KeyUnknown :
publicKeyMethod = tr ( " Unknown protection method, %1-bit key " ) . arg ( currentCertificateInfo . getKeySize ( ) ) ;
break ;
default :
Q_ASSERT ( false ) ;
break ;
}
addName ( pdf : : PDFCertificateInfo : : CountryName , tr ( " Country " ) ) ;
addName ( pdf : : PDFCertificateInfo : : OrganizationName , tr ( " Organization " ) ) ;
addName ( pdf : : PDFCertificateInfo : : OrganizationalUnitName , tr ( " Org. unit " ) ) ;
addName ( pdf : : PDFCertificateInfo : : DistinguishedName , tr ( " Name " ) ) ;
addName ( pdf : : PDFCertificateInfo : : StateOrProvinceName , tr ( " State " ) ) ;
addName ( pdf : : PDFCertificateInfo : : SerialNumber , tr ( " Serial number " ) ) ;
addName ( pdf : : PDFCertificateInfo : : LocalityName , tr ( " Locality " ) ) ;
addName ( pdf : : PDFCertificateInfo : : Title , tr ( " Title " ) ) ;
addName ( pdf : : PDFCertificateInfo : : Surname , tr ( " Surname " ) ) ;
addName ( pdf : : PDFCertificateInfo : : GivenName , tr ( " Forename " ) ) ;
addName ( pdf : : PDFCertificateInfo : : Initials , tr ( " Initials " ) ) ;
addName ( pdf : : PDFCertificateInfo : : Pseudonym , tr ( " Pseudonym " ) ) ;
addName ( pdf : : PDFCertificateInfo : : GenerationalQualifier , tr ( " Qualifier " ) ) ;
addName ( pdf : : PDFCertificateInfo : : Email , tr ( " Email " ) ) ;
QTreeWidgetItem * publicKeyItem = new QTreeWidgetItem ( certRoot , QStringList ( publicKeyMethod ) ) ;
publicKeyItem - > setIcon ( 0 , infoIcon ) ;
QDateTime notValidBefore = currentCertificateInfo . getNotValidBefore ( ) . toLocalTime ( ) ;
QDateTime notValidAfter = currentCertificateInfo . getNotValidAfter ( ) . toLocalTime ( ) ;
if ( notValidBefore . isValid ( ) )
{
QTreeWidgetItem * item = new QTreeWidgetItem ( certRoot , QStringList ( QString ( " Valid from: %2 " ) . arg ( notValidBefore . toString ( Qt : : DefaultLocaleShortDate ) ) ) ) ;
item - > setIcon ( 0 , infoIcon ) ;
}
if ( notValidAfter . isValid ( ) )
{
QTreeWidgetItem * item = new QTreeWidgetItem ( certRoot , QStringList ( QString ( " Valid to: %2 " ) . arg ( notValidAfter . toString ( Qt : : DefaultLocaleShortDate ) ) ) ) ;
item - > setIcon ( 0 , infoIcon ) ;
}
QStringList keyUsages ;
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageDigitalSignature ) )
{
keyUsages < < tr ( " Digital signatures " ) ;
}
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageNonRepudiation ) )
{
keyUsages < < tr ( " Non-repudiation " ) ;
}
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageKeyEncipherment ) )
{
keyUsages < < tr ( " Key encipherement " ) ;
}
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageDataEncipherment ) )
{
keyUsages < < tr ( " Application data encipherement " ) ;
}
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageAgreement ) )
{
keyUsages < < tr ( " Key agreement " ) ;
}
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageCertSign ) )
{
keyUsages < < tr ( " Verify signatures on certificates " ) ;
}
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageCrlSign ) )
{
keyUsages < < tr ( " Verify signatures on revocation information " ) ;
}
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageEncipherOnly ) )
{
keyUsages < < tr ( " Encipher data during key agreement " ) ;
}
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageDecipherOnly ) )
{
keyUsages < < tr ( " Decipher data during key agreement " ) ;
}
2020-07-06 16:31:41 +02:00
if ( keyUsageFlags . testFlag ( pdf : : PDFCertificateInfo : : KeyUsageExtended_TIMESTAMP ) )
{
keyUsages < < tr ( " Trusted timestamping " ) ;
}
2020-06-20 18:20:57 +02:00
if ( ! keyUsages . isEmpty ( ) )
{
QTreeWidgetItem * keyUsageRoot = new QTreeWidgetItem ( certRoot , QStringList ( tr ( " Key usages " ) ) ) ;
keyUsageRoot - > setIcon ( 0 , infoIcon ) ;
for ( const QString & keyUsage : keyUsages )
{
QTreeWidgetItem * keyUsageItem = new QTreeWidgetItem ( keyUsageRoot , QStringList ( keyUsage ) ) ;
keyUsageItem - > setIcon ( 0 , infoIcon ) ;
}
}
}
}
ui - > signatureTreeWidget - > addTopLevelItem ( rootItem ) ;
}
ui - > signatureTreeWidget - > expandToDepth ( 1 ) ;
ui - > signatureTreeWidget - > setUpdatesEnabled ( true ) ;
}
2019-12-07 17:59:03 +01:00
void PDFSidebarWidget : : onPageButtonClicked ( )
{
QObject * pushButton = sender ( ) ;
for ( const auto & pageInfo : m_pageInfo )
{
if ( pageInfo . second . button = = pushButton )
{
Q_ASSERT ( ! isEmpty ( pageInfo . first ) ) ;
selectPage ( pageInfo . first ) ;
break ;
}
}
}
2019-11-29 19:10:29 +01:00
void PDFSidebarWidget : : onOutlineItemClicked ( const QModelIndex & index )
{
if ( const pdf : : PDFAction * action = m_outlineTreeModel - > getAction ( index ) )
{
emit actionTriggered ( action ) ;
}
}
2019-12-07 17:59:03 +01:00
void PDFSidebarWidget : : onThumbnailsSizeChanged ( int size )
{
2020-02-23 18:59:54 +01:00
const int thumbnailsSize = pdf : : PDFWidgetUtils : : getPixelSize ( this , size * 10.0 ) ;
2019-12-07 17:59:03 +01:00
Q_ASSERT ( thumbnailsSize > 0 ) ;
m_thumbnailsModel - > setThumbnailsSize ( thumbnailsSize ) ;
}
2019-12-03 19:24:43 +01:00
void PDFSidebarWidget : : onAttachmentCustomContextMenuRequested ( const QPoint & pos )
{
if ( const pdf : : PDFFileSpecification * fileSpecification = m_attachmentsTreeModel - > getFileSpecification ( ui - > attachmentsTreeView - > indexAt ( pos ) ) )
{
QMenu menu ( this ) ;
QAction * action = new QAction ( QApplication : : style ( ) - > standardIcon ( QStyle : : SP_DialogSaveButton , nullptr , ui - > attachmentsTreeView ) , tr ( " Save to File... " ) , & menu ) ;
auto onSaveTriggered = [ this , fileSpecification ] ( )
{
const pdf : : PDFEmbeddedFile * platformFile = fileSpecification - > getPlatformFile ( ) ;
if ( platformFile & & platformFile - > isValid ( ) )
{
QString defaultFileName = QStandardPaths : : writableLocation ( QStandardPaths : : DocumentsLocation ) + QDir : : separator ( ) + fileSpecification - > getPlatformFileName ( ) ;
QString saveFileName = QFileDialog : : getSaveFileName ( this , tr ( " Save attachment " ) , defaultFileName ) ;
if ( ! saveFileName . isEmpty ( ) )
{
try
{
QByteArray data = m_document - > getDecodedStream ( platformFile - > getStream ( ) ) ;
QFile file ( saveFileName ) ;
if ( file . open ( QFile : : WriteOnly | QFile : : Truncate ) )
{
file . write ( data ) ;
file . close ( ) ;
}
else
{
QMessageBox : : critical ( this , tr ( " Error " ) , tr ( " Failed to save attachment to file. %1 " ) . arg ( file . errorString ( ) ) ) ;
}
}
catch ( pdf : : PDFException e )
{
QMessageBox : : critical ( this , tr ( " Error " ) , tr ( " Failed to save attachment to file. %1 " ) . arg ( e . getMessage ( ) ) ) ;
}
}
}
else
{
QMessageBox : : critical ( this , tr ( " Error " ) , tr ( " Failed to save attachment to file. Attachment is corrupted. " ) ) ;
}
} ;
connect ( action , & QAction : : triggered , this , onSaveTriggered ) ;
menu . addAction ( action ) ;
menu . exec ( ui - > attachmentsTreeView - > viewport ( ) - > mapToGlobal ( pos ) ) ;
}
}
2019-12-08 19:20:36 +01:00
void PDFSidebarWidget : : onThumbnailClicked ( const QModelIndex & index )
{
if ( index . isValid ( ) )
{
m_proxy - > goToPage ( m_thumbnailsModel - > getPageIndex ( index ) ) ;
}
}
2020-06-27 17:28:03 +02:00
void PDFSidebarWidget : : onSignatureCustomContextMenuRequested ( const QPoint & pos )
{
if ( QTreeWidgetItem * item = ui - > signatureTreeWidget - > itemAt ( pos ) )
{
QVariant data = item - > data ( 0 , Qt : : UserRole ) ;
if ( data . isValid ( ) )
{
const pdf : : PDFCertificateInfo & info = m_certificateInfos . at ( data . toInt ( ) ) ;
if ( ! m_certificateStore - > contains ( info ) )
{
QMenu menu ;
QAction * action = menu . addAction ( tr ( " Add to trusted certificates " ) ) ;
auto addCertificate = [ this , info ] ( )
{
if ( QMessageBox : : question ( this , tr ( " Add to Trusted Certificate Store " ) , tr ( " Are you sure want to add '%1' to the trusted certificate store? " ) . arg ( info . getName ( pdf : : PDFCertificateInfo : : CommonName ) ) ) = = QMessageBox : : Yes )
{
if ( ! m_certificateStore - > add ( pdf : : PDFCertificateStore : : EntryType : : User , info ) )
{
QMessageBox : : critical ( this , tr ( " Trusted Certificate Store Error " ) , tr ( " Failed to add certificate to the trusted certificate store. " ) ) ;
}
}
} ;
connect ( action , & QAction : : triggered , this , addCertificate ) ;
menu . exec ( ui - > signatureTreeWidget - > viewport ( ) - > mapToGlobal ( pos ) ) ;
}
}
}
}
2019-12-04 19:18:40 +01:00
void PDFSidebarWidget : : paintEvent ( QPaintEvent * event )
{
Q_UNUSED ( event ) ;
QPainter painter ( this ) ;
painter . fillRect ( rect ( ) , QColor ( 64 , 64 , 64 ) ) ;
}
2019-11-28 18:20:32 +01:00
} // namespace pdfviewer