diff --git a/CMakeLists.txt b/CMakeLists.txt index 9d54764c8..c8e4426d3 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,474 +1,473 @@ cmake_minimum_required(VERSION 3.0) # KDE Application Version, managed by release script set (KDE_APPLICATIONS_VERSION_MAJOR "18") set (KDE_APPLICATIONS_VERSION_MINOR "07") set (KDE_APPLICATIONS_VERSION_MICRO "70") set (KDE_APPLICATIONS_VERSION "${KDE_APPLICATIONS_VERSION_MAJOR}.${KDE_APPLICATIONS_VERSION_MINOR}.${KDE_APPLICATIONS_VERSION_MICRO}") project(okular VERSION 1.4.${KDE_APPLICATIONS_VERSION_MICRO}) set(QT_REQUIRED_VERSION "5.8.0") set(KF5_REQUIRED_VERSION "5.33.0") find_package(ECM 5.33.0 CONFIG REQUIRED) set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${ECM_MODULE_PATH}) include(ECMInstallIcons) include(ECMSetupVersion) include(ECMOptionalAddSubdirectory) include(GenerateExportHeader) include(FeatureSummary) include(ECMAddAppIcon) include(KDECompilerSettings NO_POLICY_SCOPE) include(KDEInstallDirs) include(KDECMakeSettings) include(ECMAddTests) include(ECMAddAppIcon) include(CMakePackageConfigHelpers) ecm_setup_version(${PROJECT_VERSION} VARIABLE_PREFIX OKULAR VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/core/version.h" PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/Okular5ConfigVersion.cmake") find_package(Qt5 ${QT_REQUIRED_VERSION} CONFIG REQUIRED COMPONENTS Core DBus Test Widgets PrintSupport Svg Qml Quick) find_package(Qt5 ${QT_REQUIRED_VERSION} OPTIONAL_COMPONENTS TextToSpeech) if (NOT Qt5TextToSpeech_FOUND) message(STATUS "Qt5TextToSpeech not found, speech features will be disabled") else() add_definitions(-DHAVE_SPEECH) endif() if(NOT CMAKE_VERSION VERSION_LESS "3.10.0") # CMake 3.9+ warns about automoc on files without Q_OBJECT, and doesn't know about other macros. # 3.10+ lets us provide more macro names that require automoc. list(APPEND CMAKE_AUTOMOC_MACRO_NAMES "OKULAR_EXPORT_PLUGIN") endif() set(optionalComponents) if (ANDROID) # we want to make sure that generally all components are found set(optionalComponents "OPTIONAL_COMPONENTS") endif() find_package(KF5 ${KF5_REQUIRED_VERSION} REQUIRED COMPONENTS Archive Bookmarks Completion Config ConfigWidgets CoreAddons Crash IconThemes KIO Parts ThreadWeaver WindowSystem ${optionalComponents} DocTools JS Wallet ) if(KF5Wallet_FOUND) add_definitions(-DWITH_KWALLET=1) endif() if(KF5JS_FOUND) add_definitions(-DWITH_KJS=1) endif() if(NOT WIN32 AND NOT ANDROID) find_package(KF5 ${KF5_REQUIRED_VERSION} REQUIRED COMPONENTS Activities ) set_package_properties("KF5Activities" PROPERTIES DESCRIPTION "Activities interface library" URL "https://api.kde.org/frameworks/kactivities/html/" TYPE RECOMMENDED PURPOSE "Required for Activities integration.") endif() find_package(KF5Kirigami2) set_package_properties(KF5Kirigami2 PROPERTIES DESCRIPTION "A QtQuick based components set" PURPOSE "Required at runtime by the mobile app" TYPE RUNTIME ) find_package(Phonon4Qt5 CONFIG REQUIRED) find_package(KDEExperimentalPurpose) set_package_properties(KDEExperimentalPurpose PROPERTIES DESCRIPTION "A framework for services and actions integration" PURPOSE "Required for enabling the share menu in Okular" TYPE OPTIONAL ) if (KDEExperimentalPurpose_FOUND) set(PURPOSE_FOUND 1) else() set(PURPOSE_FOUND 0) endif() set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${CMAKE_SOURCE_DIR}/cmake/modules) find_package(ZLIB REQUIRED) # This is here instead of in generators since we use if(Poppler_Qt5_FOUND) in autotests/ find_package(Poppler "0.12.1" COMPONENTS Qt5) set_package_properties("Poppler" PROPERTIES TYPE RECOMMENDED PURPOSE "Support for PDF files in okular.") add_definitions(-DQT_USE_FAST_CONCATENATION -DQT_USE_FAST_OPERATOR_PLUS) add_definitions(-DTRANSLATION_DOMAIN="okular") add_definitions(-DQT_NO_URL_CAST_FROM_STRING) include_directories(${CMAKE_CURRENT_SOURCE_DIR} ${PHONON_INCLUDES} core/synctex ${ZLIB_INCLUDE_DIR} ${CMAKE_BINARY_DIR}/core) option(BUILD_OKULARKIRIGAMI "Builds the touch-friendly frontend" ON) if (BUILD_OKULARKIRIGAMI) add_subdirectory( mobile ) endif() option(BUILD_COVERAGE "Build the project with gcov support" OFF) if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") if (NOT CMAKE_CXX_COMPILER_VERSION VERSION_LESS "5.0.0") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsuggest-override" ) endif() endif() if(BUILD_COVERAGE) set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fprofile-arcs -ftest-coverage") set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -lgcov") endif() add_subdirectory( ui ) add_subdirectory( shell ) add_subdirectory( generators ) add_subdirectory( autotests ) add_subdirectory( conf/autotests ) if(KF5DocTools_FOUND) add_subdirectory(doc) endif() include(OkularConfigureChecks.cmake) if(NOT WIN32) set(MATH_LIB m) else(NOT WIN32) set(MATH_LIB) endif(NOT WIN32) # okularcore set(okularcore_SRCS core/action.cpp core/annotations.cpp core/area.cpp core/audioplayer.cpp core/bookmarkmanager.cpp core/chooseenginedialog.cpp core/document.cpp core/documentcommands.cpp core/fontinfo.cpp core/form.cpp core/generator.cpp core/generator_p.cpp core/misc.cpp core/movie.cpp core/observer.cpp core/debug.cpp core/page.cpp core/pagecontroller.cpp core/pagesize.cpp core/pagetransition.cpp core/rotationjob.cpp core/scripter.cpp core/sound.cpp core/sourcereference.cpp core/textdocumentgenerator.cpp core/textdocumentsettings.cpp core/textpage.cpp core/tilesmanager.cpp core/utils.cpp core/view.cpp core/fileprinter.cpp core/signatureutils.cpp core/script/event.cpp core/synctex/synctex_parser.c core/synctex/synctex_parser_utils.c ) qt5_add_resources(okularcore_SRCS core/script/builtin.qrc ) ki18n_wrap_ui(okularcore_SRCS conf/textdocumentsettings.ui ) install( FILES core/action.h core/annotations.h core/area.h core/document.h core/fontinfo.h core/form.h core/generator.h core/global.h core/page.h core/pagesize.h core/pagetransition.h core/signatureutils.h core/sound.h core/sourcereference.h core/textdocumentgenerator.h core/textdocumentsettings.h core/textpage.h core/tile.h core/utils.h core/fileprinter.h core/observer.h ${CMAKE_CURRENT_BINARY_DIR}/core/version.h ${CMAKE_CURRENT_BINARY_DIR}/core/okularcore_export.h ${CMAKE_CURRENT_BINARY_DIR}/settings_core.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/okular/core COMPONENT Devel) install( FILES interfaces/configinterface.h interfaces/guiinterface.h interfaces/printinterface.h interfaces/saveinterface.h interfaces/viewerinterface.h DESTINATION ${KDE_INSTALL_INCLUDEDIR}/okular/interfaces COMPONENT Devel) ki18n_wrap_ui(okularcore_SRCS core/chooseenginewidget.ui ) kconfig_add_kcfg_files(okularcore_SRCS conf/settings_core.kcfgc) add_library(okularcore SHARED ${okularcore_SRCS}) generate_export_header(okularcore BASE_NAME okularcore EXPORT_FILE_NAME "${CMAKE_CURRENT_BINARY_DIR}/core/okularcore_export.h") if (ANDROID) set(fileName ${CMAKE_BINARY_DIR}/Okular5Core-android-dependencies.xml) file(WRITE "${fileName}" "\n" "\n" "\n") install(FILES ${fileName} DESTINATION ${KDE_INSTALL_LIBDIR}) endif() # Special handling for linking okularcore on OSX/Apple IF(APPLE) SET(OKULAR_IOKIT "-framework IOKit" CACHE STRING "Apple IOKit framework") ENDIF(APPLE) # Extra library needed by imported synctex code on Windows if(WIN32) set(SHLWAPI shlwapi) endif(WIN32) target_link_libraries(okularcore PRIVATE ${OKULAR_IOKIT} ${SHLWAPI} KF5::Archive KF5::KIOCore KF5::KIOWidgets KF5::I18n KF5::ThreadWeaver KF5::Bookmarks Phonon::phonon4qt5 ${MATH_LIB} ${ZLIB_LIBRARIES} PUBLIC # these are included from the installed headers KF5::CoreAddons KF5::XmlGui KF5::ConfigGui Qt5::PrintSupport Qt5::Widgets ) if (KF5Wallet_FOUND) target_link_libraries(okularcore PRIVATE KF5::Wallet) endif() if (KF5JS_FOUND) target_sources(okularcore PRIVATE core/script/executor_kjs.cpp core/script/kjs_app.cpp core/script/kjs_console.cpp core/script/kjs_data.cpp core/script/kjs_document.cpp core/script/kjs_field.cpp core/script/kjs_fullscreen.cpp core/script/kjs_field.cpp core/script/kjs_spell.cpp core/script/kjs_util.cpp core/script/kjs_event.cpp ) target_link_libraries(okularcore PRIVATE KF5::JS KF5::JSApi) endif() set_target_properties(okularcore PROPERTIES VERSION 9.0.0 SOVERSION 9 OUTPUT_NAME Okular5Core EXPORT_NAME Core) install(TARGETS okularcore EXPORT Okular5Targets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES conf/okular.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR}) install(FILES conf/okular_core.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR}) install(FILES core/okularGenerator.desktop DESTINATION ${KDE_INSTALL_KSERVICETYPES5DIR}) # okularpart set(okularpart_conf_SRCS conf/preferencesdialog.cpp conf/dlgaccessibility.cpp conf/dlgdebug.cpp conf/dlgeditor.cpp conf/dlggeneral.cpp conf/dlgannotations.cpp conf/dlgperformance.cpp conf/dlgpresentation.cpp conf/editannottooldialog.cpp conf/editdrawingtooldialog.cpp conf/widgetannottools.cpp conf/widgetconfigurationtoolsbase.cpp conf/widgetdrawingtools.cpp ) set(okularpart_SRCS ${okularpart_conf_SRCS} part.cpp extensions.cpp ui/embeddedfilesdialog.cpp ui/annotwindow.cpp ui/annotationmodel.cpp ui/annotationpopup.cpp ui/annotationpropertiesdialog.cpp ui/annotationproxymodels.cpp ui/annotationtools.cpp ui/annotationwidgets.cpp ui/bookmarklist.cpp - ui/certificateviewer.cpp ui/debug_ui.cpp ui/drawingtoolactions.cpp ui/fileprinterpreview.cpp ui/findbar.cpp ui/formwidgets.cpp ui/guiutils.cpp ui/ktreeviewsearchline.cpp ui/latexrenderer.cpp ui/minibar.cpp ui/okmenutitle.cpp ui/pageitemdelegate.cpp ui/pagepainter.cpp ui/pagesizelabel.cpp ui/pageviewannotator.cpp ui/pageviewmouseannotation.cpp ui/pageview.cpp ui/magnifierview.cpp ui/pageviewutils.cpp ui/presentationsearchbar.cpp ui/presentationwidget.cpp ui/propertiesdialog.cpp ui/searchlineedit.cpp ui/searchwidget.cpp ui/sidebar.cpp ui/side_reviews.cpp ui/snapshottaker.cpp ui/thumbnaillist.cpp ui/toc.cpp ui/tocmodel.cpp ui/toolaction.cpp ui/videowidget.cpp ui/layers.cpp ui/signaturemodel.cpp ui/signaturepanel.cpp ui/signaturewidgets.cpp ) if (Qt5TextToSpeech_FOUND) set(okularpart_SRCS ${okularpart_SRCS} ui/tts.cpp) endif() ki18n_wrap_ui(okularpart_SRCS conf/dlgaccessibilitybase.ui conf/dlgeditorbase.ui conf/dlggeneralbase.ui conf/dlgannotationsbase.ui conf/dlgperformancebase.ui conf/dlgpresentationbase.ui ) kconfig_add_kcfg_files(okularpart_SRCS conf/settings.kcfgc) add_library(okularpart SHARED ${okularpart_SRCS}) generate_export_header(okularpart BASE_NAME okularpart) target_link_libraries(okularpart okularcore ${MATH_LIB} Qt5::Svg Phonon::phonon4qt5 KF5::Archive KF5::Bookmarks KF5::I18n KF5::IconThemes KF5::ItemViews KF5::KIOCore KF5::KIOFileWidgets KF5::KIOWidgets KF5::Parts KF5::Solid KF5::WindowSystem ) if(KF5Wallet_FOUND) target_link_libraries(okularpart KF5::Wallet) endif() if (KDEExperimentalPurpose_FOUND) target_link_libraries(okularpart KDEExperimental::PurposeWidgets) endif() set_target_properties(okularpart PROPERTIES PREFIX "") if (Qt5TextToSpeech_FOUND) target_link_libraries(okularpart Qt5::TextToSpeech) endif() install(TARGETS okularpart DESTINATION ${KDE_INSTALL_PLUGINDIR}) ########### install files ############### install(FILES okular.upd DESTINATION ${KDE_INSTALL_DATADIR}/kconf_update) install( FILES okular_part.desktop DESTINATION ${KDE_INSTALL_KSERVICES5DIR} ) install( FILES part.rc part-viewermode.rc DESTINATION ${KDE_INSTALL_KXMLGUI5DIR}/okular ) install( FILES okular.categories DESTINATION ${KDE_INSTALL_CONFDIR} ) ########### cmake files ################# set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/Okular5") configure_package_config_file( "${CMAKE_CURRENT_SOURCE_DIR}/Okular5Config.cmake.in" "${CMAKE_CURRENT_BINARY_DIR}/Okular5Config.cmake" INSTALL_DESTINATION ${CMAKECONFIG_INSTALL_DIR} PATH_VARS INCLUDE_INSTALL_DIR CMAKE_INSTALL_PREFIX ) install(FILES "${CMAKE_CURRENT_BINARY_DIR}/Okular5Config.cmake" "${CMAKE_CURRENT_BINARY_DIR}/Okular5ConfigVersion.cmake" DESTINATION "${CMAKECONFIG_INSTALL_DIR}" COMPONENT Devel ) install(EXPORT Okular5Targets DESTINATION "${CMAKECONFIG_INSTALL_DIR}" FILE Okular5Targets.cmake NAMESPACE Okular::) ########### summary ################# feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES) diff --git a/ui/certificateviewer.cpp b/ui/certificateviewer.cpp deleted file mode 100644 index c39464eb9..000000000 --- a/ui/certificateviewer.cpp +++ /dev/null @@ -1,160 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * - * * - * 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 "certificateviewer.h" - -#include - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "core/form.h" -#include "core/page.h" -#include "core/document.h" -#include "core/sourcereference.h" -#include "core/form.h" -#include "settings.h" -#include "guiutils.h" - - -CertificateViewerModel::CertificateViewerModel( Okular::SignatureInfo *sigInfo, QObject * parent ) - : QAbstractTableModel( parent ) -{ - m_sigProperties.append( qMakePair( i18n("Subject Name"), sigInfo->signerName() ) ); - m_sigProperties.append( qMakePair( i18n("Subject Distinguished Name"), sigInfo->signerSubjectDN() ) ); - m_sigProperties.append( qMakePair( i18n("Signing Time"), sigInfo->signingTime().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); - m_sigProperties.append( qMakePair( i18n("Hash Algorithm"), GuiUtils::getReadableHashAlgorithm( sigInfo->hashAlgorithm() ) ) ); - m_sigProperties.append( qMakePair( i18n("Signature Status"), GuiUtils::getReadableSigState( sigInfo->signatureStatus() ) ) ); - m_sigProperties.append( qMakePair( i18n("Certificate Status"), GuiUtils::getReadableCertState( sigInfo->certificateStatus() ) ) ); - m_sigProperties.append( qMakePair( i18n("Signature Data"), QString::fromUtf8( sigInfo->signature().toHex(' ') ) ) ); - m_sigProperties.append( qMakePair( i18n("Location"), QString( sigInfo->location() ) ) ); - m_sigProperties.append( qMakePair( i18n("Reason"), QString( sigInfo->reason() ) ) ); - m_sigProperties.append( qMakePair( QStringLiteral("----------"), QString("------Certificate Properties--------") ) ); - - Okular::CertificateInfo *certInfo = sigInfo->certificateInfo(); - m_sigProperties.append( qMakePair( i18n("Version"), QString("V" + QString::number(certInfo->version()) ) ) ); - m_sigProperties.append( qMakePair( i18n("Issuer Name"), certInfo->issuerInfo(Okular::CertificateInfo::CommonName) ) ); - m_sigProperties.append( qMakePair( i18n("Issuer Distinguished Name"), certInfo->issuerInfo(Okular::CertificateInfo::DistinguishedName) ) ); - m_sigProperties.append( qMakePair( i18n("Serial Number"), certInfo->serialNumber().toHex(' ') ) ); - m_sigProperties.append( qMakePair( i18n("Validity Start"), certInfo->validityStart().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); - m_sigProperties.append( qMakePair( i18n("Validity End"), certInfo->validityEnd().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); - m_sigProperties.append( qMakePair( i18n("Public Key"), certInfo->publicKey().toHex(' ') ) ); - m_sigProperties.append( qMakePair( i18n("Is Self Signed"), certInfo->isSelfSigned() ? QString("true") : QString("false") ) ); -} - - -int CertificateViewerModel::columnCount( const QModelIndex & ) const -{ - return 2; -} - -int CertificateViewerModel::rowCount( const QModelIndex & ) const -{ - return m_sigProperties.size(); -} - -QVariant CertificateViewerModel::data( const QModelIndex &index, int role ) const -{ - int row = index.row(); - if ( !index.isValid() || row < 0 || row >= m_sigProperties.count() ) - return QVariant(); - - switch ( role ) - { - case Qt::DisplayRole: - case Qt::ToolTipRole: - switch ( index.column() ) - { - case 0: - return m_sigProperties[row].first; - case 1: - return m_sigProperties[row].second; - default: - return QString(); - } - case PropertyValueRole: - return m_sigProperties[row].second; - } - - return QVariant(); -} - -QVariant CertificateViewerModel::headerData( int section, Qt::Orientation orientation, int role ) const -{ - if ( role == Qt::TextAlignmentRole ) - return QVariant( Qt::AlignLeft ); - - if ( orientation != Qt::Horizontal || role != Qt::DisplayRole) - return QVariant(); - - switch ( section ) - { - case 0: - return i18n("Property"); - case 1: - return i18n("Value"); - default: - return QVariant(); - } -} - - -CertificateViewer::CertificateViewer( Okular::SignatureInfo *sigInfo, QWidget *parent ) - : QDialog( parent ), m_sigInfo( sigInfo ) -{ - setModal( true ); - setFixedSize( QSize( 450, 500 )); - setWindowTitle( i18n("Signature Properties") ); - - auto sigPropLabel = new QLabel( this ); - sigPropLabel->setText( i18n("Signature Properties:") ); - - auto sigPropTree = new QTreeView( this ); - sigPropTree->setIndentation( 0 ); - m_sigPropModel = new CertificateViewerModel( m_sigInfo, this ); - sigPropTree->setModel( m_sigPropModel ); - connect( sigPropTree, &QTreeView::clicked, this, &CertificateViewer::updateText ); - - m_sigPropText = new QTextEdit( this ); - m_sigPropText->setReadOnly( true ); - - auto btnBox = new QDialogButtonBox( QDialogButtonBox::Close, this ); - btnBox->button( QDialogButtonBox::Close )->setDefault( true ); - connect( btnBox, &QDialogButtonBox::rejected, this, &CertificateViewer::reject ); - - auto mainLayout = new QVBoxLayout( this ); - mainLayout->addWidget( sigPropLabel ); - mainLayout->addWidget( sigPropTree ); - mainLayout->addWidget( m_sigPropText ); - mainLayout->addWidget( btnBox ); - setLayout( mainLayout ); -} - -void CertificateViewer::updateText( const QModelIndex &index ) -{ - m_sigPropText->setText( m_sigPropModel->data( index, CertificateViewerModel::PropertyValueRole ).toString() ); -} diff --git a/ui/certificateviewer.h b/ui/certificateviewer.h deleted file mode 100644 index 6616d40b1..000000000 --- a/ui/certificateviewer.h +++ /dev/null @@ -1,66 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * - * * - * 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. * - ***************************************************************************/ - -#ifndef OKULAR_CERTIFICATEVIEWER_H -#define OKULAR_CERTIFICATEVIEWER_H - -#include -#include -#include -#include -#include "core/signatureutils.h" -#include "core/observer.h" -#include "fileprinterpreview.h" -#include "signaturemodel.h" - -class QTextEdit; - -namespace Okular { - class Document; - class FormFieldSignature; - class SignatureInfo; -} - -class CertificateViewerModel : public QAbstractTableModel -{ - Q_OBJECT - - public: - explicit CertificateViewerModel( Okular::SignatureInfo *sigInfo, QObject * parent = nullptr ); - - enum { - PropertyValueRole = Qt::UserRole - }; - - int columnCount( const QModelIndex &parent = QModelIndex() ) const override; - int rowCount( const QModelIndex &parent = QModelIndex() ) const override; - QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override; - QVariant headerData( int section, Qt::Orientation orientation, int role ) const override; - - private: - QVector< QPair > m_sigProperties; -}; - -class CertificateViewer : public QDialog -{ - Q_OBJECT - - public: - CertificateViewer( Okular::SignatureInfo *sigInfo, QWidget *parent ); - - private Q_SLOTS: - void updateText( const QModelIndex &index ); - - private: - CertificateViewerModel *m_sigPropModel; - QTextEdit *m_sigPropText; - Okular::SignatureInfo *m_sigInfo; -}; - -#endif diff --git a/ui/formwidgets.cpp b/ui/formwidgets.cpp index 239ce8774..db92bcefc 100644 --- a/ui/formwidgets.cpp +++ b/ui/formwidgets.cpp @@ -1,1247 +1,1246 @@ /*************************************************************************** * Copyright (C) 2007 by Pino Toscano * * Copyright (C) 2017 Klarälvdalens Datakonsult AB, a KDAB Group * * company, info@kdab.com. Work sponsored by the * * LiMux project of the city of Munich * * Copyright (C) 2018 Intevation GmbH * * * * 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 "formwidgets.h" #include "pageviewutils.h" #include "signaturewidgets.h" -#include "certificateviewer.h" #include #include #include #include #include #include #include #include #include #include // local includes #include "core/form.h" #include "core/document.h" #include "core/signatureutils.h" #include "debug_ui.h" FormWidgetsController::FormWidgetsController( Okular::Document *doc ) : QObject( doc ), m_doc( doc ) { // emit changed signal when a form has changed connect( this, &FormWidgetsController::formTextChangedByUndoRedo, this, &FormWidgetsController::changed ); connect( this, &FormWidgetsController::formListChangedByUndoRedo, this, &FormWidgetsController::changed ); connect( this, &FormWidgetsController::formComboChangedByUndoRedo, this, &FormWidgetsController::changed ); // connect form modification signals to and from document connect( this, &FormWidgetsController::formTextChangedByWidget, doc, &Okular::Document::editFormText ); connect( doc, &Okular::Document::formTextChangedByUndoRedo, this, &FormWidgetsController::formTextChangedByUndoRedo ); connect( this, &FormWidgetsController::formListChangedByWidget, doc, &Okular::Document::editFormList ); connect( doc, &Okular::Document::formListChangedByUndoRedo, this, &FormWidgetsController::formListChangedByUndoRedo ); connect( this, &FormWidgetsController::formComboChangedByWidget, doc, &Okular::Document::editFormCombo ); connect( doc, &Okular::Document::formComboChangedByUndoRedo, this, &FormWidgetsController::formComboChangedByUndoRedo ); connect( this, &FormWidgetsController::formButtonsChangedByWidget, doc, &Okular::Document::editFormButtons ); connect( doc, &Okular::Document::formButtonsChangedByUndoRedo, this, &FormWidgetsController::slotFormButtonsChangedByUndoRedo ); // Connect undo/redo signals connect( this, &FormWidgetsController::requestUndo, doc, &Okular::Document::undo ); connect( this, &FormWidgetsController::requestRedo, doc, &Okular::Document::redo ); connect( doc, &Okular::Document::canUndoChanged, this, &FormWidgetsController::canUndoChanged ); connect( doc, &Okular::Document::canRedoChanged, this, &FormWidgetsController::canRedoChanged ); // Connect the generic formWidget refresh signal connect( doc, &Okular::Document::refreshFormWidget, this, &FormWidgetsController::refreshFormWidget ); } FormWidgetsController::~FormWidgetsController() { } void FormWidgetsController::signalAction( Okular::Action *a ) { emit action( a ); } void FormWidgetsController::registerRadioButton( FormWidgetIface *fwButton, Okular::FormFieldButton *formButton ) { if ( !fwButton ) return; QAbstractButton *button = dynamic_cast(fwButton); if ( !button ) { qWarning() << "fwButton is not a QAbstractButton" << fwButton; return; } QList< RadioData >::iterator it = m_radios.begin(), itEnd = m_radios.end(); const int id = formButton->id(); m_buttons.insert( id, button ); for ( ; it != itEnd; ++it ) { const QList< int >::const_iterator idsIt = qFind( (*it).ids, id ); if ( idsIt != (*it).ids.constEnd() ) { qCDebug(OkularUiDebug) << "Adding id" << id << "To group including" << (*it).ids; (*it).group->addButton( button ); (*it).group->setId( button, id ); return; } } const QList< int > siblings = formButton->siblings(); RadioData newdata; newdata.ids = siblings; newdata.ids.append( id ); newdata.group = new QButtonGroup(); newdata.group->addButton( button ); newdata.group->setId( button, id ); // Groups of 1 (like checkboxes) can't be exclusive if (siblings.isEmpty()) newdata.group->setExclusive( false ); connect( newdata.group, SIGNAL( buttonClicked(QAbstractButton* ) ), this, SLOT( slotButtonClicked( QAbstractButton* ) ) ); m_radios.append( newdata ); } void FormWidgetsController::dropRadioButtons() { QList< RadioData >::iterator it = m_radios.begin(), itEnd = m_radios.end(); for ( ; it != itEnd; ++it ) { delete (*it).group; } m_radios.clear(); m_buttons.clear(); } bool FormWidgetsController::canUndo() { return m_doc->canUndo(); } bool FormWidgetsController::canRedo() { return m_doc->canRedo(); } void FormWidgetsController::slotButtonClicked( QAbstractButton *button ) { int pageNumber = -1; CheckBoxEdit *check = qobject_cast< CheckBoxEdit * >( button ); if ( check ) { // Checkboxes need to be uncheckable so if clicking a checked one // disable the exclusive status temporarily and uncheck it Okular::FormFieldButton *formButton = static_cast( check->formField() ); if ( formButton->state() ) { const bool wasExclusive = button->group()->exclusive(); button->group()->setExclusive(false); check->setChecked(false); button->group()->setExclusive(wasExclusive); } pageNumber = check->pageItem()->pageNumber(); } else if ( RadioButtonEdit *radio = qobject_cast< RadioButtonEdit * >( button ) ) { pageNumber = radio->pageItem()->pageNumber(); } const QList< QAbstractButton* > buttons = button->group()->buttons(); QList< bool > checked; QList< bool > prevChecked; QList< Okular::FormFieldButton*> formButtons; foreach ( QAbstractButton* button, buttons ) { checked.append( button->isChecked() ); Okular::FormFieldButton *formButton = static_cast( dynamic_cast(button)->formField() ); formButtons.append( formButton ); prevChecked.append( formButton->state() ); } if (checked != prevChecked) emit formButtonsChangedByWidget( pageNumber, formButtons, checked ); if ( check ) { // The formButtonsChangedByWidget signal changes the value of the underlying // Okular::FormField of the checkbox. We need to execute the activiation // action after this. check->doActivateAction(); } } void FormWidgetsController::slotFormButtonsChangedByUndoRedo( int pageNumber, const QList< Okular::FormFieldButton* > & formButtons) { foreach ( Okular::FormFieldButton* formButton, formButtons ) { int id = formButton->id(); QAbstractButton* button = m_buttons[id]; CheckBoxEdit *check = qobject_cast< CheckBoxEdit * >( button ); if ( check ) { emit refreshFormWidget( check->formField() ); } // temporarily disable exclusiveness of the button group // since it breaks doing/redoing steps into which all the checkboxes // are unchecked const bool wasExclusive = button->group()->exclusive(); button->group()->setExclusive(false); bool checked = formButton->state(); button->setChecked( checked ); button->group()->setExclusive(wasExclusive); button->setFocus(); } emit changed( pageNumber ); } FormWidgetIface * FormWidgetFactory::createWidget( Okular::FormField * ff, QWidget * parent ) { FormWidgetIface * widget = nullptr; switch ( ff->type() ) { case Okular::FormField::FormButton: { Okular::FormFieldButton * ffb = static_cast< Okular::FormFieldButton * >( ff ); switch ( ffb->buttonType() ) { case Okular::FormFieldButton::Push: widget = new PushButtonEdit( ffb, parent ); break; case Okular::FormFieldButton::CheckBox: widget = new CheckBoxEdit( ffb, parent ); break; case Okular::FormFieldButton::Radio: widget = new RadioButtonEdit( ffb, parent ); break; default: ; } break; } case Okular::FormField::FormText: { Okular::FormFieldText * fft = static_cast< Okular::FormFieldText * >( ff ); switch ( fft->textType() ) { case Okular::FormFieldText::Multiline: widget = new TextAreaEdit( fft, parent ); break; case Okular::FormFieldText::Normal: widget = new FormLineEdit( fft, parent ); break; case Okular::FormFieldText::FileSelect: widget = new FileEdit( fft, parent ); break; } break; } case Okular::FormField::FormChoice: { Okular::FormFieldChoice * ffc = static_cast< Okular::FormFieldChoice * >( ff ); switch ( ffc->choiceType() ) { case Okular::FormFieldChoice::ListBox: widget = new ListEdit( ffc, parent ); break; case Okular::FormFieldChoice::ComboBox: widget = new ComboEdit( ffc, parent ); break; } break; } case Okular::FormField::FormSignature: { Okular::FormFieldSignature * ffs = static_cast< Okular::FormFieldSignature * >( ff ); if ( ffs->isVisible() && ffs->signatureType() != Okular::FormFieldSignature::UnknownType ) widget = new SignatureEdit( ffs, parent ); break; } default: ; } if ( ff->isReadOnly() ) widget->setVisibility( false ); return widget; } FormWidgetIface::FormWidgetIface( QWidget * w, Okular::FormField * ff ) : m_controller( nullptr ), m_ff( ff ), m_widget( w ), m_pageItem( nullptr ) { } FormWidgetIface::~FormWidgetIface() { m_ff = nullptr; } Okular::NormalizedRect FormWidgetIface::rect() const { return m_ff->rect(); } void FormWidgetIface::setWidthHeight( int w, int h ) { m_widget->resize( w, h ); } void FormWidgetIface::moveTo( int x, int y ) { m_widget->move( x, y ); } bool FormWidgetIface::setVisibility( bool visible ) { bool hadfocus = m_widget->hasFocus(); if ( hadfocus ) m_widget->clearFocus(); m_widget->setVisible( visible ); return hadfocus; } void FormWidgetIface::setCanBeFilled( bool fill ) { m_widget->setEnabled( fill ); } void FormWidgetIface::setPageItem( PageViewItem *pageItem ) { m_pageItem = pageItem; } void FormWidgetIface::setFormField( Okular::FormField *field ) { m_ff = field; } Okular::FormField* FormWidgetIface::formField() const { return m_ff; } PageViewItem* FormWidgetIface::pageItem() const { return m_pageItem; } void FormWidgetIface::setFormWidgetsController( FormWidgetsController *controller ) { m_controller = controller; QObject *obj = dynamic_cast< QObject * > ( this ); QObject::connect( m_controller, &FormWidgetsController::refreshFormWidget, obj, [this] ( Okular::FormField *form ) { slotRefresh ( form ); }); } void FormWidgetIface::slotRefresh( Okular::FormField * form ) { if ( m_ff != form ) { return; } setVisibility( form->isVisible() && !form->isReadOnly() ); m_widget->setEnabled( !form->isReadOnly() ); } PushButtonEdit::PushButtonEdit( Okular::FormFieldButton * button, QWidget * parent ) : QPushButton( parent ), FormWidgetIface( this, button ) { setText( button->caption() ); setVisible( button->isVisible() ); setCursor( Qt::ArrowCursor ); } CheckBoxEdit::CheckBoxEdit( Okular::FormFieldButton * button, QWidget * parent ) : QCheckBox( parent ), FormWidgetIface( this, button ) { setText( button->caption() ); setVisible( button->isVisible() ); setCursor( Qt::ArrowCursor ); } void CheckBoxEdit::setFormWidgetsController( FormWidgetsController *controller ) { Okular::FormFieldButton *form = static_cast(m_ff); FormWidgetIface::setFormWidgetsController( controller ); m_controller->registerRadioButton( this, form ); setChecked( form->state() ); } void CheckBoxEdit::doActivateAction() { Okular::FormFieldButton *form = static_cast(m_ff); if ( form->activationAction() ) m_controller->signalAction( form->activationAction() ); } void CheckBoxEdit::slotRefresh( Okular::FormField * form ) { if ( form != m_ff ) { return; } FormWidgetIface::slotRefresh( form ); Okular::FormFieldButton *button = static_cast(m_ff); bool oldState = isChecked(); bool newState = button->state(); if ( oldState != newState ) { setChecked( button->state() ); doActivateAction(); } } RadioButtonEdit::RadioButtonEdit( Okular::FormFieldButton * button, QWidget * parent ) : QRadioButton( parent ), FormWidgetIface( this, button ) { setText( button->caption() ); setVisible( button->isVisible() ); setCursor( Qt::ArrowCursor ); } void RadioButtonEdit::setFormWidgetsController( FormWidgetsController *controller ) { Okular::FormFieldButton *form = static_cast(m_ff); FormWidgetIface::setFormWidgetsController( controller ); m_controller->registerRadioButton( this, form ); setChecked( form->state() ); } FormLineEdit::FormLineEdit( Okular::FormFieldText * text, QWidget * parent ) : QLineEdit( parent ), FormWidgetIface( this, text ) { int maxlen = text->maximumLength(); if ( maxlen >= 0 ) setMaxLength( maxlen ); setAlignment( text->textAlignment() ); setText( text->text() ); if ( text->isPassword() ) setEchoMode( QLineEdit::Password ); m_prevCursorPos = cursorPosition(); m_prevAnchorPos = cursorPosition(); connect( this, &QLineEdit::textEdited, this, &FormLineEdit::slotChanged ); connect( this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged ); setVisible( text->isVisible() ); } void FormLineEdit::setFormWidgetsController(FormWidgetsController* controller) { FormWidgetIface::setFormWidgetsController(controller); connect( m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &FormLineEdit::slotHandleTextChangedByUndoRedo ); } bool FormLineEdit::event( QEvent* e ) { if ( e->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast< QKeyEvent* >( e ); if ( keyEvent == QKeySequence::Undo ) { emit m_controller->requestUndo(); return true; } else if ( keyEvent == QKeySequence::Redo ) { emit m_controller->requestRedo(); return true; } } return QLineEdit::event( e ); } void FormLineEdit::contextMenuEvent( QContextMenuEvent* event ) { QMenu *menu = createStandardContextMenu(); QList actionList = menu->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct }; QAction *kundo = KStandardAction::create( KStandardAction::Undo, m_controller, SIGNAL( requestUndo() ), menu ); QAction *kredo = KStandardAction::create( KStandardAction::Redo, m_controller, SIGNAL( requestRedo() ), menu ); connect( m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled ); connect( m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled ); kundo->setEnabled( m_controller->canUndo() ); kredo->setEnabled( m_controller->canRedo() ); QAction *oldUndo, *oldRedo; oldUndo = actionList[UndoAct]; oldRedo = actionList[RedoAct]; menu->insertAction( oldUndo, kundo ); menu->insertAction( oldRedo, kredo ); menu->removeAction( oldUndo ); menu->removeAction( oldRedo ); menu->exec( event->globalPos() ); delete menu; } void FormLineEdit::slotChanged() { Okular::FormFieldText *form = static_cast(m_ff); QString contents = text(); int cursorPos = cursorPosition(); if ( contents != form->text() ) { m_controller->formTextChangedByWidget( pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos ); } m_prevCursorPos = cursorPos; m_prevAnchorPos = cursorPos; if ( hasSelectedText() ) { if ( cursorPos == selectionStart() ) { m_prevAnchorPos = selectionStart() + selectedText().size(); } else { m_prevAnchorPos = selectionStart(); } } } void FormLineEdit::slotHandleTextChangedByUndoRedo( int pageNumber, Okular::FormFieldText* textForm, const QString & contents, int cursorPos, int anchorPos ) { Q_UNUSED(pageNumber); if ( textForm != m_ff || contents == text() ) { return; } disconnect( this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged ); setText(contents); setCursorPosition(anchorPos); cursorForward( true, cursorPos - anchorPos ); connect( this, &QLineEdit::cursorPositionChanged, this, &FormLineEdit::slotChanged ); m_prevCursorPos = cursorPos; m_prevAnchorPos = anchorPos; setFocus(); } void FormLineEdit::slotRefresh( Okular::FormField *form ) { if (form != m_ff) { return; } FormWidgetIface::slotRefresh( form ); Okular::FormFieldText *text = static_cast ( form ); setText( text->text() ); } TextAreaEdit::TextAreaEdit( Okular::FormFieldText * text, QWidget * parent ) : KTextEdit( parent ), FormWidgetIface( this, text ) { setAcceptRichText( text->isRichText() ); setCheckSpellingEnabled( text->canBeSpellChecked() ); setAlignment( text->textAlignment() ); setPlainText( text->text() ); setUndoRedoEnabled( false ); connect( this, &QTextEdit::textChanged, this, &TextAreaEdit::slotChanged ); connect( this, &QTextEdit::cursorPositionChanged, this, &TextAreaEdit::slotChanged ); connect( this, &KTextEdit::aboutToShowContextMenu, this, &TextAreaEdit::slotUpdateUndoAndRedoInContextMenu ); m_prevCursorPos = textCursor().position(); m_prevAnchorPos = textCursor().anchor(); setVisible( text->isVisible() ); } bool TextAreaEdit::event( QEvent* e ) { if ( e->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast< QKeyEvent* >(e); if ( keyEvent == QKeySequence::Undo ) { emit m_controller->requestUndo(); return true; } else if ( keyEvent == QKeySequence::Redo ) { emit m_controller->requestRedo(); return true; } } return KTextEdit::event( e ); } void TextAreaEdit::slotUpdateUndoAndRedoInContextMenu( QMenu* menu ) { if ( !menu ) return; QList actionList = menu->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, ClearAct, SelectAllAct, NCountActs }; QAction *kundo = KStandardAction::create( KStandardAction::Undo, m_controller, SIGNAL( requestUndo() ), menu ); QAction *kredo = KStandardAction::create( KStandardAction::Redo, m_controller, SIGNAL( requestRedo() ), menu ); connect(m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled ); connect(m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled ); kundo->setEnabled( m_controller->canUndo() ); kredo->setEnabled( m_controller->canRedo() ); QAction *oldUndo, *oldRedo; oldUndo = actionList[UndoAct]; oldRedo = actionList[RedoAct]; menu->insertAction( oldUndo, kundo ); menu->insertAction( oldRedo, kredo ); menu->removeAction( oldUndo ); menu->removeAction( oldRedo ); } void TextAreaEdit::setFormWidgetsController( FormWidgetsController* controller ) { FormWidgetIface::setFormWidgetsController( controller ); connect( m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &TextAreaEdit::slotHandleTextChangedByUndoRedo ); } void TextAreaEdit::slotHandleTextChangedByUndoRedo( int pageNumber, Okular::FormFieldText* textForm, const QString & contents, int cursorPos, int anchorPos ) { Q_UNUSED(pageNumber); if ( textForm != m_ff ) { return; } setPlainText( contents ); QTextCursor c = textCursor(); c.setPosition( anchorPos ); c.setPosition( cursorPos,QTextCursor::KeepAnchor ); m_prevCursorPos = cursorPos; m_prevAnchorPos = anchorPos; setTextCursor( c ); setFocus(); } void TextAreaEdit::slotChanged() { // happens on destruction if (!m_ff) return; Okular::FormFieldText *form = static_cast(m_ff); QString contents = toPlainText(); int cursorPos = textCursor().position(); if (contents != form->text()) { m_controller->formTextChangedByWidget( pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos ); } m_prevCursorPos = cursorPos; m_prevAnchorPos = textCursor().anchor(); } void TextAreaEdit::slotRefresh( Okular::FormField *form ) { if (form != m_ff) { return; } FormWidgetIface::slotRefresh( form ); Okular::FormFieldText *text = static_cast ( form ); setPlainText( text->text() ); } FileEdit::FileEdit( Okular::FormFieldText * text, QWidget * parent ) : KUrlRequester( parent ), FormWidgetIface( this, text ) { setMode( KFile::File | KFile::ExistingOnly | KFile::LocalOnly ); setFilter( i18n( "*|All Files" ) ); setUrl( QUrl::fromUserInput( text->text() ) ); lineEdit()->setAlignment( text->textAlignment() ); m_prevCursorPos = lineEdit()->cursorPosition(); m_prevAnchorPos = lineEdit()->cursorPosition(); connect( this, &KUrlRequester::textChanged, this, &FileEdit::slotChanged ); connect( lineEdit(), &QLineEdit::cursorPositionChanged, this, &FileEdit::slotChanged ); setVisible( text->isVisible() ); } void FileEdit::setFormWidgetsController( FormWidgetsController* controller ) { FormWidgetIface::setFormWidgetsController( controller ); connect( m_controller, &FormWidgetsController::formTextChangedByUndoRedo, this, &FileEdit::slotHandleFileChangedByUndoRedo ); } bool FileEdit::eventFilter( QObject* obj, QEvent* event ) { if ( obj == lineEdit() ) { if ( event->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast< QKeyEvent* >( event ); if ( keyEvent == QKeySequence::Undo ) { emit m_controller->requestUndo(); return true; } else if ( keyEvent == QKeySequence::Redo ) { emit m_controller->requestRedo(); return true; } } else if( event->type() == QEvent::ContextMenu ) { QContextMenuEvent *contextMenuEvent = static_cast< QContextMenuEvent* >( event ); QMenu *menu = ( (QLineEdit*) lineEdit() )->createStandardContextMenu(); QList< QAction* > actionList = menu->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct }; QAction *kundo = KStandardAction::create( KStandardAction::Undo, m_controller, SIGNAL( requestUndo() ), menu ); QAction *kredo = KStandardAction::create( KStandardAction::Redo, m_controller, SIGNAL( requestRedo() ), menu ); connect(m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled ); connect(m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled ); kundo->setEnabled( m_controller->canUndo() ); kredo->setEnabled( m_controller->canRedo() ); QAction *oldUndo, *oldRedo; oldUndo = actionList[UndoAct]; oldRedo = actionList[RedoAct]; menu->insertAction( oldUndo, kundo ); menu->insertAction( oldRedo, kredo ); menu->removeAction( oldUndo ); menu->removeAction( oldRedo ); menu->exec( contextMenuEvent->globalPos() ); delete menu; return true; } } return KUrlRequester::eventFilter( obj, event ); } void FileEdit::slotChanged() { // Make sure line edit's text matches url expansion if ( text() != url().toLocalFile() ) this->setText( url().toLocalFile() ); Okular::FormFieldText *form = static_cast(m_ff); QString contents = text(); int cursorPos = lineEdit()->cursorPosition(); if (contents != form->text()) { m_controller->formTextChangedByWidget( pageItem()->pageNumber(), form, contents, cursorPos, m_prevCursorPos, m_prevAnchorPos ); } m_prevCursorPos = cursorPos; m_prevAnchorPos = cursorPos; if ( lineEdit()->hasSelectedText() ) { if ( cursorPos == lineEdit()->selectionStart() ) { m_prevAnchorPos = lineEdit()->selectionStart() + lineEdit()->selectedText().size(); } else { m_prevAnchorPos = lineEdit()->selectionStart(); } } } void FileEdit::slotHandleFileChangedByUndoRedo( int pageNumber, Okular::FormFieldText* form, const QString & contents, int cursorPos, int anchorPos ) { Q_UNUSED(pageNumber); if ( form != m_ff || contents == text() ) { return; } disconnect( this, SIGNAL( cursorPositionChanged( int, int ) ), this, SLOT( slotChanged() ) ); setText( contents ); lineEdit()->setCursorPosition( anchorPos ); lineEdit()->cursorForward( true, cursorPos - anchorPos ); connect( this, SIGNAL(cursorPositionChanged( int, int ) ), this, SLOT( slotChanged() ) ); m_prevCursorPos = cursorPos; m_prevAnchorPos = anchorPos; setFocus(); } ListEdit::ListEdit( Okular::FormFieldChoice * choice, QWidget * parent ) : QListWidget( parent ), FormWidgetIface( this, choice ) { addItems( choice->choices() ); setSelectionMode( choice->multiSelect() ? QAbstractItemView::ExtendedSelection : QAbstractItemView::SingleSelection ); setVerticalScrollMode( QAbstractItemView::ScrollPerPixel ); QList< int > selectedItems = choice->currentChoices(); if ( choice->multiSelect() ) { foreach ( int index, selectedItems ) if ( index >= 0 && index < count() ) item( index )->setSelected( true ); } else { if ( selectedItems.count() == 1 && selectedItems.at(0) >= 0 && selectedItems.at(0) < count() ) { setCurrentRow( selectedItems.at(0) ); scrollToItem( item( selectedItems.at(0) ) ); } } connect( this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged ); setVisible( choice->isVisible() ); setCursor( Qt::ArrowCursor ); } void ListEdit::setFormWidgetsController( FormWidgetsController* controller ) { FormWidgetIface::setFormWidgetsController( controller ); connect( m_controller, &FormWidgetsController::formListChangedByUndoRedo, this, &ListEdit::slotHandleFormListChangedByUndoRedo ); } void ListEdit::slotSelectionChanged() { QList< QListWidgetItem * > selection = selectedItems(); QList< int > rows; foreach( const QListWidgetItem * item, selection ) rows.append( row( item ) ); Okular::FormFieldChoice *form = static_cast(m_ff); if ( rows != form->currentChoices() ) { m_controller->formListChangedByWidget( pageItem()->pageNumber(), form, rows ); } } void ListEdit::slotHandleFormListChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice* listForm, const QList< int > & choices ) { Q_UNUSED(pageNumber); if ( m_ff != listForm ) { return; } disconnect( this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged ); for(int i=0; i < count(); i++) { item( i )->setSelected( choices.contains(i) ); } connect( this, &QListWidget::itemSelectionChanged, this, &ListEdit::slotSelectionChanged ); setFocus(); } ComboEdit::ComboEdit( Okular::FormFieldChoice * choice, QWidget * parent ) : QComboBox( parent ), FormWidgetIface( this, choice ) { addItems( choice->choices() ); setEditable( true ); setInsertPolicy( NoInsert ); lineEdit()->setReadOnly( !choice->isEditable() ); QList< int > selectedItems = choice->currentChoices(); if ( selectedItems.count() == 1 && selectedItems.at(0) >= 0 && selectedItems.at(0) < count() ) setCurrentIndex( selectedItems.at(0) ); if ( choice->isEditable() && !choice->editChoice().isEmpty() ) lineEdit()->setText( choice->editChoice() ); connect( this, SIGNAL(currentIndexChanged(int)), this, SLOT(slotValueChanged()) ); connect( this, &QComboBox::editTextChanged, this, &ComboEdit::slotValueChanged ); connect( lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged ); setVisible( choice->isVisible() ); setCursor( Qt::ArrowCursor ); m_prevCursorPos = lineEdit()->cursorPosition(); m_prevAnchorPos = lineEdit()->cursorPosition(); } void ComboEdit::setFormWidgetsController(FormWidgetsController* controller) { FormWidgetIface::setFormWidgetsController(controller); connect( m_controller, &FormWidgetsController::formComboChangedByUndoRedo, this, &ComboEdit::slotHandleFormComboChangedByUndoRedo); } void ComboEdit::slotValueChanged() { const QString text = lineEdit()->text(); Okular::FormFieldChoice *form = static_cast(m_ff); QString prevText; if ( form->currentChoices().isEmpty() ) { prevText = form->editChoice(); } else { prevText = form->choices()[form->currentChoices()[0]]; } int cursorPos = lineEdit()->cursorPosition(); if ( text != prevText ) { m_controller->formComboChangedByWidget( pageItem()->pageNumber(), form, currentText(), cursorPos, m_prevCursorPos, m_prevAnchorPos ); } prevText = text; m_prevCursorPos = cursorPos; m_prevAnchorPos = cursorPos; if ( lineEdit()->hasSelectedText() ) { if ( cursorPos == lineEdit()->selectionStart() ) { m_prevAnchorPos = lineEdit()->selectionStart() + lineEdit()->selectedText().size(); } else { m_prevAnchorPos = lineEdit()->selectionStart(); } } } void ComboEdit::slotHandleFormComboChangedByUndoRedo( int pageNumber, Okular::FormFieldChoice* form, const QString & text, int cursorPos, int anchorPos ) { Q_UNUSED(pageNumber); if ( m_ff != form ) { return; } // Determine if text corrisponds to an index choices int index = -1; for ( int i = 0; i < count(); i++ ) { if ( itemText(i) == text ) { index = i; } } m_prevCursorPos = cursorPos; m_prevAnchorPos = anchorPos; disconnect( lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged ); const bool isCustomValue = index == -1; if ( isCustomValue ) { setEditText( text ); } else { setCurrentIndex( index ); } lineEdit()->setCursorPosition( anchorPos ); lineEdit()->cursorForward( true, cursorPos - anchorPos ); connect( lineEdit(), &QLineEdit::cursorPositionChanged, this, &ComboEdit::slotValueChanged ); setFocus(); } void ComboEdit::contextMenuEvent( QContextMenuEvent* event ) { QMenu *menu = lineEdit()->createStandardContextMenu(); QList actionList = menu->actions(); enum { UndoAct, RedoAct, CutAct, CopyAct, PasteAct, DeleteAct, SelectAllAct }; QAction *kundo = KStandardAction::create( KStandardAction::Undo, m_controller, SIGNAL( requestUndo() ), menu ); QAction *kredo = KStandardAction::create( KStandardAction::Redo, m_controller, SIGNAL( requestRedo() ), menu ); connect( m_controller, &FormWidgetsController::canUndoChanged, kundo, &QAction::setEnabled ); connect( m_controller, &FormWidgetsController::canRedoChanged, kredo, &QAction::setEnabled ); kundo->setEnabled( m_controller->canUndo() ); kredo->setEnabled( m_controller->canRedo() ); QAction *oldUndo, *oldRedo; oldUndo = actionList[UndoAct]; oldRedo = actionList[RedoAct]; menu->insertAction( oldUndo, kundo ); menu->insertAction( oldRedo, kredo ); menu->removeAction( oldUndo ); menu->removeAction( oldRedo ); menu->exec( event->globalPos() ); delete menu; } bool ComboEdit::event( QEvent* e ) { if ( e->type() == QEvent::KeyPress ) { QKeyEvent *keyEvent = static_cast< QKeyEvent* >(e); if ( keyEvent == QKeySequence::Undo ) { emit m_controller->requestUndo(); return true; } else if ( keyEvent == QKeySequence::Redo ) { emit m_controller->requestRedo(); return true; } } return QComboBox::event( e ); } SignatureEdit::SignatureEdit( Okular::FormFieldSignature * signature, QWidget * parent ) : QAbstractButton( parent ), FormWidgetIface( this, signature ), m_leftMouseButtonPressed( false ) { // Okular::FormFieldSignature *sigField = static_cast< Okular::FormFieldSignature * >( formField() ); // m_sigInfo = sigField->validate(); setCheckable( false ); setCursor( Qt::PointingHandCursor ); connect( this, &SignatureEdit::clicked, this, &SignatureEdit::slotShowSummary ); } bool SignatureEdit::event( QEvent * e ) { switch ( e->type() ) { case QEvent::MouseButtonPress: { QMouseEvent *ev = static_cast< QMouseEvent * >( e ); if ( ev->button() == Qt::LeftButton ) { m_leftMouseButtonPressed = true; update(); } mousePressEvent( ev ); break; } case QEvent::MouseButtonRelease: { QMouseEvent *ev = static_cast< QMouseEvent * >( e ); m_leftMouseButtonPressed = false; if ( ev->button() == Qt::LeftButton) { update(); } mouseReleaseEvent( ev ); break; } default: break; } return QAbstractButton::event( e ); } void SignatureEdit::contextMenuEvent( QContextMenuEvent * event ) { QMenu *menu = new QMenu( this ); QAction *sigVal = new QAction( i18n("Validate Signature"), this ); menu->addAction( sigVal ); connect( sigVal, &QAction::triggered, this, &SignatureEdit::slotShowSummary ); QAction *sigProp = new QAction( i18n("Show Signature Properties"), this ); menu->addAction( sigProp ); connect( sigProp, &QAction::triggered, this, &SignatureEdit::slotShowProperties ); menu->exec( event->globalPos() ); delete menu; } void SignatureEdit::paintEvent( QPaintEvent * ) { QPainter painter( this ); painter.setPen( Qt::black ); if ( m_leftMouseButtonPressed ) { QColor col = palette().color( QPalette::Active, QPalette::Highlight ); col.setAlpha(50); painter.setBrush( col ); } else { painter.setBrush( Qt::transparent ); } painter.drawRect( 0, 0, width()-2, height()-2 ); } Okular::SignatureInfo *SignatureEdit::validate() { Okular::FormFieldSignature *sigField = static_cast< Okular::FormFieldSignature * >( formField() ); m_sigInfo = sigField->validate(); m_signatureValidated = true; return m_sigInfo; } void SignatureEdit::slotShowSummary() { Okular::FormFieldSignature *signatureForm = static_cast< Okular::FormFieldSignature * >( formField() ); SignaturePropertiesDialog sigSummaryDlg( m_controller->m_doc, signatureForm, this ); sigSummaryDlg.exec(); } void SignatureEdit::slotShowProperties() { CertificateViewer sigPropDlg( m_sigInfo, this ); sigPropDlg.exec(); } // Code for additional action handling. // Challenge: Change preprocessor magic to C++ magic! // // The mouseRelease event is special because the PDF spec // says that the activation action takes precedence over this. // So the mouse release action is only signaled if no activation // action exists. // // For checkboxes the activation action is not triggered as // they are still triggered from the clicked signal and additionally // when the checked state changes. #define DEFINE_ADDITIONAL_ACTIONS(FormClass, BaseClass) \ void FormClass::mousePressEvent( QMouseEvent *event ) \ { \ Okular::Action *act = m_ff->additionalAction( Okular::Annotation::MousePressed ); \ if ( act ) \ { \ m_controller->signalAction( act ); \ } \ BaseClass::mousePressEvent( event ); \ } \ void FormClass::mouseReleaseEvent( QMouseEvent *event ) \ { \ if ( !QWidget::rect().contains( event->localPos().toPoint() ) ) \ { \ BaseClass::mouseReleaseEvent( event ); \ return; \ } \ Okular::Action *act = m_ff->activationAction(); \ if ( act && !qobject_cast< CheckBoxEdit* > ( this ) ) \ { \ m_controller->signalAction( act ); \ } \ else if ( ( act = m_ff->additionalAction( Okular::Annotation::MouseReleased ) ) ) \ { \ m_controller->signalAction( act ); \ } \ BaseClass::mouseReleaseEvent( event ); \ } \ void FormClass::focusInEvent( QFocusEvent *event ) \ { \ Okular::Action *act = m_ff->additionalAction( Okular::Annotation::FocusIn ); \ if ( act ) \ { \ m_controller->signalAction( act ); \ } \ BaseClass::focusInEvent( event ); \ } \ void FormClass::focusOutEvent( QFocusEvent *event ) \ { \ Okular::Action *act = m_ff->additionalAction( Okular::Annotation::FocusOut ); \ if ( act ) \ { \ m_controller->signalAction( act ); \ } \ BaseClass::focusOutEvent( event ); \ } \ void FormClass::leaveEvent( QEvent *event ) \ { \ Okular::Action *act = m_ff->additionalAction( Okular::Annotation::CursorLeaving ); \ if ( act ) \ { \ m_controller->signalAction( act ); \ } \ BaseClass::leaveEvent( event ); \ } \ void FormClass::enterEvent( QEvent *event ) \ { \ Okular::Action *act = m_ff->additionalAction( Okular::Annotation::CursorEntering ); \ if ( act ) \ { \ m_controller->signalAction( act ); \ } \ BaseClass::enterEvent( event ); \ } DEFINE_ADDITIONAL_ACTIONS( PushButtonEdit, QPushButton ) DEFINE_ADDITIONAL_ACTIONS( CheckBoxEdit, QCheckBox ) DEFINE_ADDITIONAL_ACTIONS( RadioButtonEdit, QRadioButton ) DEFINE_ADDITIONAL_ACTIONS( FormLineEdit, QLineEdit ) DEFINE_ADDITIONAL_ACTIONS( TextAreaEdit, KTextEdit ) DEFINE_ADDITIONAL_ACTIONS( FileEdit, KUrlRequester ) DEFINE_ADDITIONAL_ACTIONS( ListEdit, QListWidget ) DEFINE_ADDITIONAL_ACTIONS( ComboEdit, QComboBox ) DEFINE_ADDITIONAL_ACTIONS( SignatureEdit, QAbstractButton ) #undef DEFINE_ADDITIONAL_ACTIONS #include "moc_formwidgets.cpp" diff --git a/ui/signaturewidgets.cpp b/ui/signaturewidgets.cpp index 2b9bec9b5..0557930ab 100644 --- a/ui/signaturewidgets.cpp +++ b/ui/signaturewidgets.cpp @@ -1,168 +1,286 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * * * * 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 "signaturewidgets.h" -#include "certificateviewer.h" #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "core/form.h" #include "core/page.h" #include "core/document.h" #include "core/sourcereference.h" #include "core/form.h" #include "settings.h" #include "guiutils.h" + +CertificateViewerModel::CertificateViewerModel( Okular::SignatureInfo *sigInfo, QObject * parent ) + : QAbstractTableModel( parent ) +{ + m_sigProperties.append( qMakePair( i18n("Subject Name"), sigInfo->signerName() ) ); + m_sigProperties.append( qMakePair( i18n("Subject Distinguished Name"), sigInfo->signerSubjectDN() ) ); + m_sigProperties.append( qMakePair( i18n("Signing Time"), sigInfo->signingTime().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); + m_sigProperties.append( qMakePair( i18n("Hash Algorithm"), GuiUtils::getReadableHashAlgorithm( sigInfo->hashAlgorithm() ) ) ); + m_sigProperties.append( qMakePair( i18n("Signature Status"), GuiUtils::getReadableSigState( sigInfo->signatureStatus() ) ) ); + m_sigProperties.append( qMakePair( i18n("Certificate Status"), GuiUtils::getReadableCertState( sigInfo->certificateStatus() ) ) ); + m_sigProperties.append( qMakePair( i18n("Signature Data"), QString::fromUtf8( sigInfo->signature().toHex(' ') ) ) ); + m_sigProperties.append( qMakePair( i18n("Location"), QString( sigInfo->location() ) ) ); + m_sigProperties.append( qMakePair( i18n("Reason"), QString( sigInfo->reason() ) ) ); + m_sigProperties.append( qMakePair( QStringLiteral("----------"), QString("------Certificate Properties--------") ) ); + + Okular::CertificateInfo *certInfo = sigInfo->certificateInfo(); + m_sigProperties.append( qMakePair( i18n("Version"), QString("V" + QString::number(certInfo->version()) ) ) ); + m_sigProperties.append( qMakePair( i18n("Issuer Name"), certInfo->issuerInfo(Okular::CertificateInfo::CommonName) ) ); + m_sigProperties.append( qMakePair( i18n("Issuer Distinguished Name"), certInfo->issuerInfo(Okular::CertificateInfo::DistinguishedName) ) ); + m_sigProperties.append( qMakePair( i18n("Serial Number"), certInfo->serialNumber().toHex(' ') ) ); + m_sigProperties.append( qMakePair( i18n("Validity Start"), certInfo->validityStart().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); + m_sigProperties.append( qMakePair( i18n("Validity End"), certInfo->validityEnd().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); + m_sigProperties.append( qMakePair( i18n("Public Key"), certInfo->publicKey().toHex(' ') ) ); + m_sigProperties.append( qMakePair( i18n("Is Self Signed"), certInfo->isSelfSigned() ? QString("true") : QString("false") ) ); +} + + +int CertificateViewerModel::columnCount( const QModelIndex & ) const +{ + return 2; +} + +int CertificateViewerModel::rowCount( const QModelIndex & ) const +{ + return m_sigProperties.size(); +} + +QVariant CertificateViewerModel::data( const QModelIndex &index, int role ) const +{ + int row = index.row(); + if ( !index.isValid() || row < 0 || row >= m_sigProperties.count() ) + return QVariant(); + + switch ( role ) + { + case Qt::DisplayRole: + case Qt::ToolTipRole: + switch ( index.column() ) + { + case 0: + return m_sigProperties[row].first; + case 1: + return m_sigProperties[row].second; + default: + return QString(); + } + case PropertyValueRole: + return m_sigProperties[row].second; + } + + return QVariant(); +} + +QVariant CertificateViewerModel::headerData( int section, Qt::Orientation orientation, int role ) const +{ + if ( role == Qt::TextAlignmentRole ) + return QVariant( Qt::AlignLeft ); + + if ( orientation != Qt::Horizontal || role != Qt::DisplayRole) + return QVariant(); + + switch ( section ) + { + case 0: + return i18n("Property"); + case 1: + return i18n("Value"); + default: + return QVariant(); + } +} + + +CertificateViewer::CertificateViewer( Okular::SignatureInfo *sigInfo, QWidget *parent ) + : QDialog( parent ), m_sigInfo( sigInfo ) +{ + setModal( true ); + setFixedSize( QSize( 450, 500 )); + setWindowTitle( i18n("Signature Properties") ); + + auto sigPropLabel = new QLabel( this ); + sigPropLabel->setText( i18n("Signature Properties:") ); + + auto sigPropTree = new QTreeView( this ); + sigPropTree->setIndentation( 0 ); + m_sigPropModel = new CertificateViewerModel( m_sigInfo, this ); + sigPropTree->setModel( m_sigPropModel ); + connect( sigPropTree, &QTreeView::clicked, this, &CertificateViewer::updateText ); + + m_sigPropText = new QTextEdit( this ); + m_sigPropText->setReadOnly( true ); + + auto btnBox = new QDialogButtonBox( QDialogButtonBox::Close, this ); + btnBox->button( QDialogButtonBox::Close )->setDefault( true ); + connect( btnBox, &QDialogButtonBox::rejected, this, &SignaturePropertiesDialog::reject ); + + auto mainLayout = new QVBoxLayout( this ); + mainLayout->addWidget( sigPropLabel ); + mainLayout->addWidget( sigPropTree ); + mainLayout->addWidget( m_sigPropText ); + mainLayout->addWidget( btnBox ); + setLayout( mainLayout ); +} + +void CertificateViewer::updateText( const QModelIndex &index ) +{ + m_sigPropText->setText( m_sigPropModel->data( index, CertificateViewerModel::PropertyValueRole ).toString() ); +} + SignaturePropertiesDialog::SignaturePropertiesDialog( Okular::Document *doc, Okular::FormFieldSignature *form, QWidget *parent ) : QDialog( parent ), m_doc( doc ), m_signatureForm( form ) { setModal( true ); setWindowTitle( i18n("Signature Properties") ); m_signatureInfo = m_signatureForm->validate(); auto mainLayout = new QVBoxLayout; // signature validation status auto sigStatusBox = new QGroupBox( i18n("Validity Status") ); auto hBoxLayout = new QHBoxLayout; auto pixmapLabel = new QLabel; pixmapLabel->setPixmap( KIconLoader::global()->loadIcon( QLatin1String("application-certificate"), KIconLoader::Desktop, KIconLoader::SizeSmallMedium ) ); hBoxLayout->addWidget( pixmapLabel ); auto sigStatusFormLayout = new QFormLayout; const Okular::SignatureInfo::SignatureStatus sigStatus = m_signatureInfo->signatureStatus(); sigStatusFormLayout->addRow( i18n("Signature Validity:"), new QLabel( GuiUtils::getReadableSigState( sigStatus ) ) ); QString modString; if ( sigStatus == Okular::SignatureInfo::SignatureValid ) { if ( m_signatureInfo->signsTotalDocument() ) { modString = i18n("The document has not been modified since it was signed."); } else { modString = i18n("The revision of the document that was covered by this signature has not been modified;\n" "however there have been subsequent changes to the document."); } } else if ( sigStatus == Okular::SignatureInfo::SignatureDigestMismatch ) { modString = i18n("The document has been modified in a way not permitted by a previous signer."); } else { modString = i18n("The document integrity verification could not be completed."); } sigStatusFormLayout->addRow( i18n("Document Modifications:"), new QLabel( modString ) ); hBoxLayout->addLayout( sigStatusFormLayout ); sigStatusBox->setLayout( hBoxLayout ); mainLayout->addWidget( sigStatusBox ); // additional information auto extraInfoBox = new QGroupBox( i18n("Additional Information") ); auto extraInfoFormLayout = new QFormLayout; extraInfoFormLayout->addRow( i18n("Signed By:"), new QLabel( m_signatureInfo->signerName() ) ); extraInfoFormLayout->addRow( i18n("Signing Time:"), new QLabel( m_signatureInfo->signingTime().toString( QStringLiteral("MMM dd yyyy hh:mm:ss") ) ) ); auto getValidString = [=]( const QString &str ) -> QString { return !str.isEmpty() ? str : i18n("Not Available"); }; // optional info extraInfoFormLayout->addRow( i18n("Reason:"), new QLabel( getValidString( m_signatureInfo->reason() ) ) ); extraInfoFormLayout->addRow( i18n("Location:"), new QLabel( getValidString( m_signatureInfo->location() ) ) ); extraInfoBox->setLayout( extraInfoFormLayout ); mainLayout->addWidget( extraInfoBox ); // document version auto revisionBox = new QGroupBox( i18n("Document Version") ); auto revisionLayout = new QHBoxLayout; QVector signatureFormFields = GuiUtils::getSignatureFormFields( m_doc ); revisionLayout->addWidget( new QLabel( i18nc("Document Revision of ", "Document Revision %1 of %2", signatureFormFields.indexOf( m_signatureForm ) + 1, signatureFormFields.size() ) ) ); revisionLayout->addStretch(); auto revisionBtn = new QPushButton( i18n( "View Signed Version...") ); revisionBtn->setEnabled( !m_signatureInfo->signsTotalDocument() ); connect( revisionBtn, &QPushButton::clicked, this, &SignaturePropertiesDialog::viewSignedVersion ); revisionLayout->addWidget( revisionBtn ); revisionBox->setLayout( revisionLayout ); mainLayout->addWidget( revisionBox ); // button box auto btnBox = new QDialogButtonBox( QDialogButtonBox::Close, this ); auto certPropBtn = new QPushButton( i18n( "Vew Certificate..."), this ); certPropBtn->setVisible(m_signatureInfo->certificateInfo()->isNull()); btnBox->button( QDialogButtonBox::Close )->setDefault( true ); btnBox->addButton( certPropBtn, QDialogButtonBox::ActionRole ); connect( btnBox, &QDialogButtonBox::rejected, this, &SignaturePropertiesDialog::reject ); connect( certPropBtn, &QPushButton::clicked, this, &SignaturePropertiesDialog::viewCertificateProperties ); mainLayout->addWidget( btnBox ); setLayout( mainLayout ); resize( mainLayout->sizeHint() ); } void SignaturePropertiesDialog::viewCertificateProperties() { CertificateViewer sigPropDlg( m_signatureInfo, this ); sigPropDlg.exec(); } void SignaturePropertiesDialog::viewSignedVersion() { QByteArray data; m_doc->requestSignedRevisionData( m_signatureInfo, &data ); const QString tmpDir = QStandardPaths::writableLocation( QStandardPaths::TempLocation ); QTemporaryFile tf( tmpDir + "/revision_XXXXXX.pdf" ); if ( !tf.open() ) { KMessageBox::error( this, i18n("Could not open revision for preview" ) ); return; } tf.write(data); RevisionViewer view( tf.fileName(), this); view.exec(); tf.close(); } RevisionViewer::RevisionViewer( const QString &filename, QWidget *parent ) : FilePrinterPreview( filename, parent ) { setWindowTitle( i18n("Revision Preview") ); } RevisionViewer::~RevisionViewer() { } #include "moc_signaturewidgets.cpp" diff --git a/ui/signaturewidgets.h b/ui/signaturewidgets.h index 45766d5ec..b2b683905 100644 --- a/ui/signaturewidgets.h +++ b/ui/signaturewidgets.h @@ -1,55 +1,91 @@ /*************************************************************************** * Copyright (C) 2018 by Chinmoy Ranjan Pradhan * * * * 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. * ***************************************************************************/ #ifndef OKULAR_SIGNATUREWIDGETS_H #define OKULAR_SIGNATUREWIDGETS_H #include #include #include #include #include "core/signatureutils.h" #include "core/observer.h" #include "fileprinterpreview.h" #include "signaturemodel.h" class QTextEdit; namespace Okular { class Document; class FormFieldSignature; class SignatureInfo; } +class CertificateViewerModel : public QAbstractTableModel +{ + Q_OBJECT + + public: + explicit CertificateViewerModel( Okular::SignatureInfo *sigInfo, QObject * parent = nullptr ); + + enum { + PropertyValueRole = Qt::UserRole + }; + + int columnCount( const QModelIndex &parent = QModelIndex() ) const override; + int rowCount( const QModelIndex &parent = QModelIndex() ) const override; + QVariant data( const QModelIndex &index, int role = Qt::DisplayRole ) const override; + QVariant headerData( int section, Qt::Orientation orientation, int role ) const override; + + private: + QVector< QPair > m_sigProperties; +}; + +class CertificateViewer : public QDialog +{ + Q_OBJECT + + public: + CertificateViewer( Okular::SignatureInfo *sigInfo, QWidget *parent ); + + private Q_SLOTS: + void updateText( const QModelIndex &index ); + + private: + CertificateViewerModel *m_sigPropModel; + QTextEdit *m_sigPropText; + Okular::SignatureInfo *m_sigInfo; +}; + class SignaturePropertiesDialog : public QDialog { Q_OBJECT public: SignaturePropertiesDialog( Okular::Document *doc, Okular::FormFieldSignature *form, QWidget *parent ); private Q_SLOTS: void viewSignedVersion(); void viewCertificateProperties(); private: Okular::Document *m_doc; Okular::FormFieldSignature *m_signatureForm; Okular::SignatureInfo *m_signatureInfo; }; class RevisionViewer : public Okular::FilePrinterPreview { Q_OBJECT public: RevisionViewer( const QString &filename, QWidget *parent = nullptr ); ~RevisionViewer(); }; #endif