Dialog with information

This commit is contained in:
Jakub Melka
2019-12-20 18:56:03 +01:00
parent eefa687e3d
commit c228cf6d24
10 changed files with 520 additions and 2 deletions

View File

@ -66,7 +66,7 @@ private:
/// Object representing page in PDF document. Contains different page properties, such as
/// media box, crop box, rotation, etc. and also page content, resources.
class PDFPage
class PDFFORQTLIBSHARED_EXPORT PDFPage
{
public:
explicit PDFPage() = default;

View File

@ -35,6 +35,7 @@ LIBS += -lPDFForQtLib
SOURCES += \
main.cpp \
pdfaboutdialog.cpp \
pdfdocumentpropertiesdialog.cpp \
pdfsidebarwidget.cpp \
pdfviewermainwindow.cpp \
pdfviewersettings.cpp \
@ -43,6 +44,7 @@ SOURCES += \
HEADERS += \
pdfaboutdialog.h \
pdfdocumentpropertiesdialog.h \
pdfsidebarwidget.h \
pdfviewermainwindow.h \
pdfviewersettings.h \
@ -51,6 +53,7 @@ HEADERS += \
FORMS += \
pdfaboutdialog.ui \
pdfdocumentpropertiesdialog.ui \
pdfsidebarwidget.ui \
pdfviewermainwindow.ui \
pdfviewersettingsdialog.ui

View File

@ -0,0 +1,143 @@
// Copyright (C) 2019 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt is free software: you can redistribute it and/or modify
// 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.
//
// PdfForQt is distributed in the hope that it will be useful,
// 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
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#include "pdfdocumentpropertiesdialog.h"
#include "ui_pdfdocumentpropertiesdialog.h"
#include "pdfdocument.h"
#include "pdfwidgetutils.h"
#include <QLocale>
#include <QPageSize>
namespace pdfviewer
{
PDFDocumentPropertiesDialog::PDFDocumentPropertiesDialog(const pdf::PDFDocument* document,
const PDFFileInfo* fileInfo,
QWidget* parent) :
QDialog(parent),
ui(new Ui::PDFDocumentPropertiesDialog)
{
ui->setupUi(this);
initializeProperties(document);
initializeFileInfoProperties(fileInfo);
const int defaultWidth = PDFWidgetUtils::getPixelSize(this, 240.0);
const int defaultHeight = PDFWidgetUtils::getPixelSize(this, 200.0);
resize(defaultWidth, defaultHeight);
}
PDFDocumentPropertiesDialog::~PDFDocumentPropertiesDialog()
{
delete ui;
}
void PDFDocumentPropertiesDialog::initializeProperties(const pdf::PDFDocument* document)
{
QLocale locale;
// Initialize document properties
QTreeWidgetItem* propertiesRoot = new QTreeWidgetItem({ tr("Properties") });
const pdf::PDFDocument::Info* info = document->getInfo();
const pdf::PDFCatalog* catalog = document->getCatalog();
new QTreeWidgetItem(propertiesRoot, { tr("Title"), info->title });
new QTreeWidgetItem(propertiesRoot, { tr("Subject"), info->subject });
new QTreeWidgetItem(propertiesRoot, { tr("Author"), info->author });
new QTreeWidgetItem(propertiesRoot, { tr("Keywords"), info->keywords });
new QTreeWidgetItem(propertiesRoot, { tr("Creator"), info->creator });
new QTreeWidgetItem(propertiesRoot, { tr("Producer"), info->producer });
new QTreeWidgetItem(propertiesRoot, { tr("Creation date"), locale.toString(info->creationDate) });
new QTreeWidgetItem(propertiesRoot, { tr("Modified date"), locale.toString(info->modifiedDate) });
new QTreeWidgetItem(propertiesRoot, { tr("Version"), QString::fromLatin1(catalog->getVersion()) });
QString trapped;
switch (info->trapped)
{
case pdf::PDFDocument::Info::Trapped::True:
trapped = tr("True");
break;
case pdf::PDFDocument::Info::Trapped::False:
trapped = tr("False");
break;
case pdf::PDFDocument::Info::Trapped::Unknown:
trapped = tr("Unknown");
break;
default:
Q_ASSERT(false);
break;
}
QTreeWidgetItem* contentRoot = new QTreeWidgetItem({ tr("Content") });
const pdf::PDFInteger pageCount = catalog->getPageCount();
new QTreeWidgetItem(contentRoot, { tr("Page count"), locale.toString(pageCount) });
if (pageCount > 0)
{
const pdf::PDFPage* firstPage = catalog->getPage(0);
QSizeF pageSizeMM = firstPage->getRectMM(firstPage->getRotatedMediaBox()).size();
QPageSize pageSize(pageSizeMM, QPageSize::Millimeter, QString(), QPageSize::FuzzyOrientationMatch);
QString paperSizeString = QString("%1 x %2 mm").arg(locale.toString(pageSizeMM.width()), locale.toString(pageSizeMM.height()));
new QTreeWidgetItem(contentRoot, { tr("Paper format"), pageSize.name() });
new QTreeWidgetItem(contentRoot, { tr("Paper size"), paperSizeString });
}
new QTreeWidgetItem(contentRoot, { tr("Trapped"), trapped });
ui->propertiesTreeWidget->addTopLevelItem(propertiesRoot);
ui->propertiesTreeWidget->addTopLevelItem(contentRoot);
ui->propertiesTreeWidget->expandAll();
ui->propertiesTreeWidget->resizeColumnToContents(0);
}
void PDFDocumentPropertiesDialog::initializeFileInfoProperties(const PDFFileInfo* fileInfo)
{
QLocale locale;
// Initialize document file info
QTreeWidgetItem* fileInfoRoot = new QTreeWidgetItem({ tr("File information") });
new QTreeWidgetItem(fileInfoRoot, { tr("Name"), fileInfo->fileName });
new QTreeWidgetItem(fileInfoRoot, { tr("Directory"), fileInfo->path });
new QTreeWidgetItem(fileInfoRoot, { tr("Writable"), fileInfo->writable ? tr("Yes") : tr("No") });
QString fileSize;
if (fileInfo->fileSize > 1024 * 1024)
{
fileSize = QString("%1 MB (%2 bytes)").arg(locale.toString(fileInfo->fileSize / (1024.0 * 1024.0)), locale.toString(fileInfo->fileSize));
}
else
{
fileSize = QString("%1 kB (%2 bytes)").arg(locale.toString(fileInfo->fileSize / 1024.0), locale.toString(fileInfo->fileSize));
}
new QTreeWidgetItem(fileInfoRoot, { tr("Size"), fileSize });
new QTreeWidgetItem(fileInfoRoot, { tr("Created date"), locale.toString(fileInfo->creationTime) });
new QTreeWidgetItem(fileInfoRoot, { tr("Modified date"), locale.toString(fileInfo->lastModifiedTime) });
new QTreeWidgetItem(fileInfoRoot, { tr("Last read date"), locale.toString(fileInfo->lastReadTime) });
ui->fileInfoTreeWidget->addTopLevelItem(fileInfoRoot);
ui->fileInfoTreeWidget->expandAll();
ui->fileInfoTreeWidget->resizeColumnToContents(0);
}
} // namespace pdfviewer

View File

@ -0,0 +1,68 @@
// Copyright (C) 2019 Jakub Melka
//
// This file is part of PdfForQt.
//
// PdfForQt is free software: you can redistribute it and/or modify
// 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.
//
// PdfForQt is distributed in the hope that it will be useful,
// 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
// along with PDFForQt. If not, see <https://www.gnu.org/licenses/>.
#ifndef PDFDOCUMENTPROPERTIESDIALOG_H
#define PDFDOCUMENTPROPERTIESDIALOG_H
#include "pdfglobal.h"
#include <QDialog>
namespace Ui
{
class PDFDocumentPropertiesDialog;
}
namespace pdf
{
class PDFDocument;
}
namespace pdfviewer
{
struct PDFFileInfo
{
QString fileName;
QString path;
pdf::PDFInteger fileSize = 0;
bool writable = false;
QDateTime creationTime;
QDateTime lastModifiedTime;
QDateTime lastReadTime;
};
class PDFDocumentPropertiesDialog : public QDialog
{
Q_OBJECT
public:
explicit PDFDocumentPropertiesDialog(const pdf::PDFDocument* document,
const PDFFileInfo* fileInfo,
QWidget* parent);
virtual ~PDFDocumentPropertiesDialog() override;
private:
Ui::PDFDocumentPropertiesDialog* ui;
void initializeProperties(const pdf::PDFDocument* document);
void initializeFileInfoProperties(const PDFFileInfo* fileInfo);
};
} // namespace pdfviewer
#endif // PDFDOCUMENTPROPERTIESDIALOG_H

View File

@ -0,0 +1,141 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PDFDocumentPropertiesDialog</class>
<widget class="QDialog" name="PDFDocumentPropertiesDialog">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>807</width>
<height>609</height>
</rect>
</property>
<property name="windowTitle">
<string>Document Properties</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout">
<item>
<widget class="QTabWidget" name="tabWidget">
<property name="currentIndex">
<number>0</number>
</property>
<widget class="QWidget" name="propertiesTab">
<attribute name="title">
<string>Properties</string>
</attribute>
<layout class="QVBoxLayout" name="propertiesLayout" stretch="3,2">
<item>
<widget class="QGroupBox" name="documentPropertiesGroupBox">
<property name="title">
<string>Properties</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_2">
<item>
<widget class="QTreeWidget" name="propertiesTreeWidget">
<property name="columnCount">
<number>2</number>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">2</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
<item>
<widget class="QGroupBox" name="fileInfoGroupBox">
<property name="title">
<string>File Information</string>
</property>
<layout class="QVBoxLayout" name="verticalLayout_3">
<item>
<widget class="QTreeWidget" name="fileInfoTreeWidget">
<property name="columnCount">
<number>2</number>
</property>
<attribute name="headerVisible">
<bool>false</bool>
</attribute>
<column>
<property name="text">
<string notr="true">1</string>
</property>
</column>
<column>
<property name="text">
<string notr="true">2</string>
</property>
</column>
</widget>
</item>
</layout>
</widget>
</item>
</layout>
</widget>
<widget class="QWidget" name="securityTab">
<attribute name="title">
<string>Security</string>
</attribute>
</widget>
</widget>
</item>
<item>
<widget class="QDialogButtonBox" name="buttonBox">
<property name="orientation">
<enum>Qt::Horizontal</enum>
</property>
<property name="standardButtons">
<set>QDialogButtonBox::Ok</set>
</property>
</widget>
</item>
</layout>
</widget>
<resources/>
<connections>
<connection>
<sender>buttonBox</sender>
<signal>accepted()</signal>
<receiver>PDFDocumentPropertiesDialog</receiver>
<slot>accept()</slot>
<hints>
<hint type="sourcelabel">
<x>248</x>
<y>254</y>
</hint>
<hint type="destinationlabel">
<x>157</x>
<y>274</y>
</hint>
</hints>
</connection>
<connection>
<sender>buttonBox</sender>
<signal>rejected()</signal>
<receiver>PDFDocumentPropertiesDialog</receiver>
<slot>reject()</slot>
<hints>
<hint type="sourcelabel">
<x>316</x>
<y>260</y>
</hint>
<hint type="destinationlabel">
<x>286</x>
<y>274</y>
</hint>
</hints>
</connection>
</connections>
</ui>

View File

@ -24,5 +24,6 @@
<file>resources/synchronize.svg</file>
<file>resources/cache.svg</file>
<file>resources/shortcuts.svg</file>
<file>resources/info.svg</file>
</qresource>
</RCC>

View File

@ -19,8 +19,9 @@
#include "ui_pdfviewermainwindow.h"
#include "pdfaboutdialog.h"
#include "pdfviewersettingsdialog.h"
#include "pdfsidebarwidget.h"
#include "pdfviewersettingsdialog.h"
#include "pdfdocumentpropertiesdialog.h"
#include "pdfdocumentreader.h"
#include "pdfvisitor.h"
@ -662,6 +663,8 @@ void PDFViewerMainWindow::updateUI(bool fullUpdate)
m_pageNumberSpinBox->setEnabled(false);
m_pageNumberLabel->setText(QString());
}
ui->actionProperties->setEnabled(m_pdfDocument);
}
else
{
@ -710,6 +713,15 @@ void PDFViewerMainWindow::openDocument(const QString& fileName)
// First close old document
closeDocument();
QFileInfo fileInfo(fileName);
m_fileInfo.fileName = fileInfo.fileName();
m_fileInfo.path = fileInfo.path();
m_fileInfo.fileSize = fileInfo.size();
m_fileInfo.writable = fileInfo.isWritable();
m_fileInfo.creationTime = fileInfo.created();
m_fileInfo.lastModifiedTime = fileInfo.lastModified();
m_fileInfo.lastReadTime = fileInfo.lastRead();
// Password callback
auto getPasswordCallback = [this](bool* ok) -> QString
{
@ -906,6 +918,14 @@ void PDFViewerMainWindow::on_actionOptions_triggered()
}
}
void PDFViewerMainWindow::on_actionProperties_triggered()
{
Q_ASSERT(m_pdfDocument);
PDFDocumentPropertiesDialog documentPropertiesDialog(m_pdfDocument.data(), &m_fileInfo, this);
documentPropertiesDialog.exec();
}
void PDFViewerMainWindow::on_actionAbout_triggered()
{
PDFAboutDialog dialog(this);

View File

@ -22,6 +22,7 @@
#include "pdfrenderer.h"
#include "pdfprogress.h"
#include "pdfviewersettings.h"
#include "pdfdocumentpropertiesdialog.h"
#include <QTreeView>
#include <QMainWindow>
@ -76,6 +77,8 @@ private slots:
void on_actionFitWidth_triggered();
void on_actionFitHeight_triggered();
void on_actionProperties_triggered();
private:
void onActionOpenTriggered();
void onActionCloseTriggered();
@ -129,6 +132,7 @@ private:
pdf::PDFProgress* m_progress;
QWinTaskbarButton* m_taskbarButton;
QWinTaskbarProgress* m_progressTaskbarIndicator;
PDFFileInfo m_fileInfo;
};
} // namespace pdfviewer

View File

@ -29,6 +29,9 @@
</property>
<addaction name="actionOpen"/>
<addaction name="actionClose"/>
<addaction name="separator"/>
<addaction name="actionProperties"/>
<addaction name="separator"/>
<addaction name="actionQuit"/>
</widget>
<widget class="QMenu" name="menuGoTo">
@ -293,6 +296,15 @@
<string>H</string>
</property>
</action>
<action name="actionProperties">
<property name="icon">
<iconset resource="pdfforqtviewer.qrc">
<normaloff>:/resources/info.svg</normaloff>:/resources/info.svg</iconset>
</property>
<property name="text">
<string>Properties</string>
</property>
</action>
</widget>
<layoutdefault spacing="6" margin="11"/>
<resources>

View File

@ -0,0 +1,126 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="30mm"
height="30mm"
viewBox="0 0 30 30"
version="1.1"
id="svg5291"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
sodipodi:docname="info.svg">
<defs
id="defs5285">
<inkscape:perspective
sodipodi:type="inkscape:persp3d"
inkscape:vp_x="0 : 15 : 1"
inkscape:vp_y="0 : 1000 : 0"
inkscape:vp_z="30 : 15 : 1"
inkscape:persp3d-origin="15 : 10 : 1"
id="perspective5921" />
</defs>
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="11.313708"
inkscape:cx="99.193261"
inkscape:cy="59.167828"
inkscape:document-units="mm"
inkscape:current-layer="layer1"
showgrid="false"
inkscape:window-width="3840"
inkscape:window-height="2035"
inkscape:window-x="-13"
inkscape:window-y="-13"
inkscape:window-maximized="1" />
<metadata
id="metadata5288">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
<dc:creator>
<cc:Agent>
<dc:title>Jakub Melka</dc:title>
</cc:Agent>
</dc:creator>
<cc:license
rdf:resource="http://creativecommons.org/licenses/by-sa/4.0/" />
</cc:Work>
<cc:License
rdf:about="http://creativecommons.org/licenses/by-sa/4.0/">
<cc:permits
rdf:resource="http://creativecommons.org/ns#Reproduction" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#Distribution" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Notice" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#Attribution" />
<cc:permits
rdf:resource="http://creativecommons.org/ns#DerivativeWorks" />
<cc:requires
rdf:resource="http://creativecommons.org/ns#ShareAlike" />
</cc:License>
</rdf:RDF>
</metadata>
<g
inkscape:label="Vrstva 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(0,-267)">
<flowRoot
xml:space="preserve"
id="flowRoot5913"
style="fill:black;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:normal;font-weight:normal;font-size:40px;line-height:1.25;letter-spacing:0px;word-spacing:0px"><flowRegion
id="flowRegion5915"><rect
id="rect5917"
width="129.22377"
height="91.747108"
x="-13.788582"
y="-33.515606" /></flowRegion><flowPara
id="flowPara5919" /></flowRoot> <g
aria-label="i"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;line-height:1.25;font-family:'Palatino Linotype';-inkscape-font-specification:'Palatino Linotype Italic';letter-spacing:0px;word-spacing:0px;fill:#000000;fill-opacity:1;stroke:none;stroke-width:0.26458332"
id="text841">
<path
d="m 14.342202,274.30462 q 0,-0.65732 0.409277,-1.15342 0.42168,-0.50849 1.016992,-0.50849 0.42168,0 0.682129,0.26045 0.260449,0.26044 0.260449,0.74414 0,0.66972 -0.384472,1.20302 -0.384473,0.5209 -0.967383,0.5209 -0.434082,0 -0.731738,-0.29765 -0.285254,-0.29766 -0.285254,-0.76895 z m -3.237012,6.92051 -0.124023,-0.28526 0.03721,-0.16123 q 1.686718,-1.21543 2.592089,-1.69912 0.917774,-0.49609 1.438672,-0.49609 0.508496,0 0.508496,0.73174 0,0.33486 -0.136425,0.95498 -0.124024,0.60771 -0.620118,2.46806 -1.351855,5.01055 -1.351855,5.92832 0,0.4961 0.347266,0.4961 0.5333,0 1.934765,-1.0542 l 0.124024,0.0372 0.136425,0.32246 -0.0248,0.14883 q -0.868164,0.66972 -1.785938,1.28984 -0.917773,0.62012 -1.314648,0.78135 -0.384473,0.17363 -0.644922,0.17363 -0.37207,0 -0.58291,-0.32246 -0.21084,-0.32246 -0.21084,-0.75654 0,-0.55811 0.148828,-1.19063 0.161231,-0.64492 0.384473,-1.42627 0.806152,-2.87734 1.141015,-4.48965 0.347266,-1.6123 0.347266,-1.97197 0,-0.42168 -0.285254,-0.42168 -0.186035,0 -0.359668,0.0992 -0.173633,0.0868 -1.562695,0.89297 z m 1.314648,10.5916 z"
style="font-style:italic;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:25.39999962px;font-family:'Palatino Linotype';-inkscape-font-specification:'Palatino Linotype Italic';stroke-width:0.26458332"
id="path870" />
</g>
<flowRoot
xml:space="preserve"
id="flowRoot843"
style="fill:black;fill-opacity:1;stroke:none;font-family:sans-serif;font-style:italic;font-weight:normal;font-size:40px;line-height:1.25;letter-spacing:0px;word-spacing:0px;-inkscape-font-specification:'sans-serif Italic';font-stretch:normal;font-variant:normal"><flowRegion
id="flowRegion845"><rect
id="rect847"
width="159.09903"
height="129.04698"
x="-37.123108"
y="-35.460152" /></flowRegion><flowPara
id="flowPara849"></flowPara></flowRoot> <path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 20.06526,273.38006 5.238482,-0.0234"
id="path853"
inkscape:connector-curvature="0" />
<path
style="fill:none;stroke:#000000;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1;stroke-miterlimit:4;stroke-dasharray:none"
d="m 22.626029,270.62098 0.0234,5.23848"
id="path853-4"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.0 KiB