qpdfviewsb/sources/pdfmodel.cpp

1334 lines
32 KiB
C++

/*
Copyright 2014 S. Razi Alavizadeh
Copyright 2018 Marshall Banana
Copyright 2013-2014, 2018 Adam Reichold
This file is part of qpdfview.
qpdfview 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.
qpdfview 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with qpdfview. If not, see <http://www.gnu.org/licenses/>.
*/
#include "pdfmodel.h"
#include <QCache>
#include <QFormLayout>
#include <QMessageBox>
#include <QSettings>
#if QT_VERSION >= QT_VERSION_CHECK(5,0,0)
#include <poppler-qt5.h>
#else
#include <poppler-qt4.h>
#endif // QT_VERSION
#include <poppler-form.h>
#include "annotationwidgets.h"
#include "formfieldwidgets.h"
#ifndef HAS_POPPLER_24
#define LOCK_ANNOTATION QMutexLocker mutexLocker(m_mutex);
#define LOCK_FORM_FIELD QMutexLocker mutexLocker(m_mutex);
#define LOCK_PAGE QMutexLocker mutexLocker(m_mutex);
#define LOCK_DOCUMENT QMutexLocker mutexLocker(&m_mutex);
#else
#define LOCK_ANNOTATION
#define LOCK_FORM_FIELD
#define LOCK_PAGE
#define LOCK_DOCUMENT
#endif // HAS_POPPLER_24
namespace
{
using namespace qpdfview;
using namespace qpdfview::Model;
Outline loadOutline(const QDomNode& parent, Poppler::Document* document)
{
Outline outline;
const QDomNodeList nodes = parent.childNodes();
outline.reserve(nodes.size());
for(int index = 0, count = nodes.size(); index < count; ++index)
{
const QDomNode node = nodes.at(index);
const QDomElement element = node.toElement();
outline.push_back(Section());
Section& section = outline.back();
section.title = element.tagName();
QScopedPointer< Poppler::LinkDestination > destination;
if(element.hasAttribute("Destination"))
{
destination.reset(new Poppler::LinkDestination(element.attribute("Destination")));
}
else if(element.hasAttribute("DestinationName"))
{
destination.reset(document->linkDestination(element.attribute("DestinationName")));
}
if(destination)
{
int page = destination->pageNumber();
qreal left = qQNaN();
qreal top = qQNaN();
page = page >= 1 ? page : 1;
page = page <= document->numPages() ? page : document->numPages();
if(destination->isChangeLeft())
{
left = destination->left();
left = left >= 0.0 ? left : 0.0;
left = left <= 1.0 ? left : 1.0;
}
if(destination->isChangeTop())
{
top = destination->top();
top = top >= 0.0 ? top : 0.0;
top = top <= 1.0 ? top : 1.0;
}
Link& link = section.link;
link.page = page;
link.left = left;
link.top = top;
const QString fileName = element.attribute("ExternalFileName");
if(!fileName.isEmpty())
{
link.urlOrFileName = fileName;
}
}
if(node.hasChildNodes())
{
section.children = loadOutline(node, document);
}
}
return outline;
}
class FontsModel : public QAbstractTableModel
{
public:
FontsModel(const QList< Poppler::FontInfo >& fonts) :
m_fonts(fonts)
{
}
int columnCount(const QModelIndex&) const
{
return 5;
}
int rowCount(const QModelIndex& parent) const
{
if(parent.isValid())
{
return 0;
}
return m_fonts.size();
}
QVariant headerData(int section, Qt::Orientation orientation, int role) const
{
if(orientation != Qt::Horizontal || role != Qt::DisplayRole)
{
return QVariant();
}
switch(section)
{
case 0:
return PdfDocument::tr("Name");
case 1:
return PdfDocument::tr("Type");
case 2:
return PdfDocument::tr("Embedded");
case 3:
return PdfDocument::tr("Subset");
case 4:
return PdfDocument::tr("File");
default:
return QVariant();
}
}
QVariant data(const QModelIndex& index, int role) const
{
if(!index.isValid() || role != Qt::DisplayRole)
{
return QVariant();
}
const Poppler::FontInfo& font = m_fonts[index.row()];
switch (index.column())
{
case 0:
return font.name();
case 1:
return font.typeName();
case 2:
return font.isEmbedded() ? PdfDocument::tr("Yes") : PdfDocument::tr("No");
case 3:
return font.isSubset() ? PdfDocument::tr("Yes") : PdfDocument::tr("No");
case 4:
return font.file();
default:
return QVariant();
}
}
private:
const QList< Poppler::FontInfo > m_fonts;
};
inline void restoreRenderHint(Poppler::Document* document, const Poppler::Document::RenderHints hints, const Poppler::Document::RenderHint hint)
{
document->setRenderHint(hint, hints.testFlag(hint));
}
typedef QSharedPointer< Poppler::TextBox > TextBox;
typedef QList< TextBox > TextBoxList;
class TextCache
{
public:
TextCache() : m_mutex(), m_cache(1 << 12) {}
bool object(const PdfPage* page, TextBoxList& textBoxes) const
{
QMutexLocker mutexLocker(&m_mutex);
if(TextBoxList* const object = m_cache.object(page))
{
textBoxes = *object;
return true;
}
return false;
}
void insert(const PdfPage* page, const TextBoxList& textBoxes)
{
QMutexLocker mutexLocker(&m_mutex);
m_cache.insert(page, new TextBoxList(textBoxes), textBoxes.count());
}
void remove(const PdfPage* page)
{
QMutexLocker mutexLocker(&m_mutex);
m_cache.remove(page);
}
private:
mutable QMutex m_mutex;
QCache< const PdfPage*, TextBoxList > m_cache;
};
Q_GLOBAL_STATIC(TextCache, textCache)
namespace Defaults
{
const bool antialiasing = true;
const bool textAntialiasing = true;
#ifdef HAS_POPPLER_18
const int textHinting = 0;
#else
const bool textHinting = false;
#endif // HAS_POPPLER_18
#ifdef HAS_POPPLER_35
const bool ignorePaperColor = false;
#endif // HAS_POPPLER_35
#ifdef HAS_POPPLER_22
const bool overprintPreview = false;
#endif // HAS_POPPLER_22
#ifdef HAS_POPPLER_24
const int thinLineMode = 0;
#endif // HAS_POPPLER_24
const int backend = 0;
} // Defaults
} // anonymous
namespace qpdfview
{
namespace Model
{
PdfAnnotation::PdfAnnotation(QMutex* mutex, Poppler::Annotation* annotation) : Annotation(),
m_mutex(mutex),
m_annotation(annotation)
{
}
PdfAnnotation::~PdfAnnotation()
{
delete m_annotation;
}
QRectF PdfAnnotation::boundary() const
{
LOCK_ANNOTATION
return m_annotation->boundary().normalized();
}
QString PdfAnnotation::contents() const
{
LOCK_ANNOTATION
return m_annotation->contents();
}
QWidget* PdfAnnotation::createWidget()
{
QWidget* widget = 0;
if(m_annotation->subType() == Poppler::Annotation::AText || m_annotation->subType() == Poppler::Annotation::AHighlight)
{
widget = new AnnotationWidget(m_mutex, m_annotation);
connect(widget, SIGNAL(wasModified()), SIGNAL(wasModified()));
}
else if(m_annotation->subType() == Poppler::Annotation::AFileAttachment)
{
widget = new FileAttachmentAnnotationWidget(m_mutex, static_cast< Poppler::FileAttachmentAnnotation* >(m_annotation));
}
connect(this, SIGNAL(destroyed()), widget, SLOT(deleteLater()));
return widget;
}
PdfFormField::PdfFormField(QMutex* mutex, Poppler::FormField* formField) : FormField(),
m_mutex(mutex),
m_formField(formField)
{
}
PdfFormField::~PdfFormField()
{
delete m_formField;
}
QRectF PdfFormField::boundary() const
{
LOCK_FORM_FIELD
return m_formField->rect().normalized();
}
QString PdfFormField::name() const
{
LOCK_FORM_FIELD
return m_formField->name();
}
QWidget* PdfFormField::createWidget()
{
QWidget* widget = 0;
if(m_formField->type() == Poppler::FormField::FormText)
{
Poppler::FormFieldText* formFieldText = static_cast< Poppler::FormFieldText* >(m_formField);
if(formFieldText->textType() == Poppler::FormFieldText::Normal)
{
widget = new NormalTextFieldWidget(m_mutex, formFieldText);
}
else if(formFieldText->textType() == Poppler::FormFieldText::Multiline)
{
widget = new MultilineTextFieldWidget(m_mutex, formFieldText);
}
}
else if(m_formField->type() == Poppler::FormField::FormChoice)
{
Poppler::FormFieldChoice* formFieldChoice = static_cast< Poppler::FormFieldChoice* >(m_formField);
if(formFieldChoice->choiceType() == Poppler::FormFieldChoice::ComboBox)
{
widget = new ComboBoxChoiceFieldWidget(m_mutex, formFieldChoice);
}
else if(formFieldChoice->choiceType() == Poppler::FormFieldChoice::ListBox)
{
widget = new ListBoxChoiceFieldWidget(m_mutex, formFieldChoice);
}
}
else if(m_formField->type() == Poppler::FormField::FormButton)
{
Poppler::FormFieldButton* formFieldButton = static_cast< Poppler::FormFieldButton* >(m_formField);
if(formFieldButton->buttonType() == Poppler::FormFieldButton::CheckBox)
{
widget = new CheckBoxChoiceFieldWidget(m_mutex, formFieldButton);
}
else if(formFieldButton->buttonType() == Poppler::FormFieldButton::Radio)
{
widget = new RadioChoiceFieldWidget(m_mutex, formFieldButton);
}
}
connect(widget, SIGNAL(wasModified()), SIGNAL(wasModified()));
return widget;
}
PdfPage::PdfPage(QMutex* mutex, Poppler::Page* page) :
m_mutex(mutex),
m_page(page)
{
}
PdfPage::~PdfPage()
{
textCache()->remove(this);
delete m_page;
}
QSizeF PdfPage::size() const
{
LOCK_PAGE
return m_page->pageSizeF();
}
QImage PdfPage::render(qreal horizontalResolution, qreal verticalResolution, Rotation rotation, QRect boundingRect) const
{
LOCK_PAGE
Poppler::Page::Rotation rotate;
switch(rotation)
{
default:
case RotateBy0:
rotate = Poppler::Page::Rotate0;
break;
case RotateBy90:
rotate = Poppler::Page::Rotate90;
break;
case RotateBy180:
rotate = Poppler::Page::Rotate180;
break;
case RotateBy270:
rotate = Poppler::Page::Rotate270;
break;
}
int x = -1;
int y = -1;
int w = -1;
int h = -1;
if(!boundingRect.isNull())
{
x = boundingRect.x();
y = boundingRect.y();
w = boundingRect.width();
h = boundingRect.height();
}
return m_page->renderToImage(horizontalResolution, verticalResolution, x, y, w, h, rotate);
}
QString PdfPage::label() const
{
LOCK_PAGE
return m_page->label();
}
QList< Link* > PdfPage::links() const
{
LOCK_PAGE
QList< Link* > links;
foreach(const Poppler::Link* link, m_page->links())
{
const QRectF boundary = link->linkArea().normalized();
if(link->linkType() == Poppler::Link::Goto)
{
const Poppler::LinkGoto* linkGoto = static_cast< const Poppler::LinkGoto* >(link);
int page = linkGoto->destination().pageNumber();
qreal left = qQNaN();
qreal top = qQNaN();
page = page >= 1 ? page : 1;
if(linkGoto->destination().isChangeLeft())
{
left = linkGoto->destination().left();
left = left >= 0.0 ? left : 0.0;
left = left <= 1.0 ? left : 1.0;
}
if(linkGoto->destination().isChangeTop())
{
top = linkGoto->destination().top();
top = top >= 0.0 ? top : 0.0;
top = top <= 1.0 ? top : 1.0;
}
if(linkGoto->isExternal())
{
links.append(new Link(boundary, linkGoto->fileName(), page));
}
else
{
links.append(new Link(boundary, page, left, top));
}
}
else if(link->linkType() == Poppler::Link::Browse)
{
const Poppler::LinkBrowse* linkBrowse = static_cast< const Poppler::LinkBrowse* >(link);
const QString url = linkBrowse->url();
links.append(new Link(boundary, url));
}
else if(link->linkType() == Poppler::Link::Execute)
{
const Poppler::LinkExecute* linkExecute = static_cast< const Poppler::LinkExecute* >(link);
const QString url = linkExecute->fileName();
links.append(new Link(boundary, url));
}
delete link;
}
return links;
}
QString PdfPage::text(const QRectF& rect) const
{
LOCK_PAGE
return m_page->text(rect).simplified();
}
QString PdfPage::cachedText(const QRectF& rect) const
{
TextBoxList textBoxes;
if(!textCache()->object(this, textBoxes))
{
{
LOCK_PAGE
foreach(Poppler::TextBox* textBox, m_page->textList())
{
textBoxes.append(TextBox(textBox));
}
}
textCache()->insert(this, textBoxes);
}
QString text;
foreach(const TextBox& textBox, textBoxes)
{
if(!rect.intersects(textBox->boundingBox()))
{
continue;
}
const QString& characters = textBox->text();
for(int index = 0; index < characters.length(); ++index)
{
if(rect.intersects(textBox->charBoundingBox(index)))
{
text.append(characters.at(index));
}
}
if(textBox->hasSpaceAfter())
{
text.append(QLatin1Char(' '));
}
}
return text.simplified();
}
QList< QRectF > PdfPage::search(const QString& text, bool matchCase, bool wholeWords) const
{
LOCK_PAGE
QList< QRectF > results;
#ifdef HAS_POPPLER_31
const Poppler::Page::SearchFlags flags((matchCase ? 0 : Poppler::Page::IgnoreCase) | (wholeWords ? Poppler::Page::WholeWords : 0));
results = m_page->search(text, flags);
#else
Q_UNUSED(wholeWords);
const Poppler::Page::SearchMode mode = matchCase ? Poppler::Page::CaseSensitive : Poppler::Page::CaseInsensitive;
#if defined(HAS_POPPLER_22)
results = m_page->search(text, mode);
#elif defined(HAS_POPPLER_14)
double left = 0.0, top = 0.0, right = 0.0, bottom = 0.0;
while(m_page->search(text, left, top, right, bottom, Poppler::Page::NextResult, mode))
{
results.append(QRectF(left, top, right - left, bottom - top));
}
#else
QRectF rect;
while(m_page->search(text, rect, Poppler::Page::NextResult, mode))
{
results.append(rect);
}
#endif // HAS_POPPLER_22 HAS_POPPLER_14
#endif // HAS_POPPLER_31
return results;
}
QList< Annotation* > PdfPage::annotations() const
{
LOCK_PAGE
QList< Annotation* > annotations;
foreach(Poppler::Annotation* annotation, m_page->annotations())
{
if(annotation->subType() == Poppler::Annotation::AText || annotation->subType() == Poppler::Annotation::AHighlight || annotation->subType() == Poppler::Annotation::AFileAttachment)
{
annotations.append(new PdfAnnotation(m_mutex, annotation));
continue;
}
delete annotation;
}
return annotations;
}
bool PdfPage::canAddAndRemoveAnnotations() const
{
#ifdef HAS_POPPLER_20
return true;
#else
QMessageBox::information(0, tr("Information"), tr("Version 0.20.1 or higher of the Poppler library is required to add or remove annotations."));
return false;
#endif // HAS_POPPLER_20
}
Annotation* PdfPage::addTextAnnotation(const QRectF& boundary, const QColor& color)
{
LOCK_PAGE
#ifdef HAS_POPPLER_20
Poppler::Annotation::Style style;
style.setColor(color);
Poppler::Annotation::Popup popup;
popup.setFlags(Poppler::Annotation::Hidden | Poppler::Annotation::ToggleHidingOnMouse);
Poppler::Annotation* annotation = new Poppler::TextAnnotation(Poppler::TextAnnotation::Linked);
annotation->setBoundary(boundary);
annotation->setStyle(style);
annotation->setPopup(popup);
m_page->addAnnotation(annotation);
return new PdfAnnotation(m_mutex, annotation);
#else
Q_UNUSED(boundary);
Q_UNUSED(color);
return 0;
#endif // HAS_POPPLER_20
}
Annotation* PdfPage::addHighlightAnnotation(const QRectF& boundary, const QColor& color)
{
LOCK_PAGE
#ifdef HAS_POPPLER_20
Poppler::Annotation::Style style;
style.setColor(color);
Poppler::Annotation::Popup popup;
popup.setFlags(Poppler::Annotation::Hidden | Poppler::Annotation::ToggleHidingOnMouse);
Poppler::HighlightAnnotation* annotation = new Poppler::HighlightAnnotation();
Poppler::HighlightAnnotation::Quad quad;
quad.points[0] = boundary.topLeft();
quad.points[1] = boundary.topRight();
quad.points[2] = boundary.bottomRight();
quad.points[3] = boundary.bottomLeft();
annotation->setHighlightQuads(QList< Poppler::HighlightAnnotation::Quad >() << quad);
annotation->setBoundary(boundary);
annotation->setStyle(style);
annotation->setPopup(popup);
m_page->addAnnotation(annotation);
return new PdfAnnotation(m_mutex, annotation);
#else
Q_UNUSED(boundary);
Q_UNUSED(color);
return 0;
#endif // HAS_POPPLER_20
}
void PdfPage::removeAnnotation(Annotation* annotation)
{
LOCK_PAGE
#ifdef HAS_POPPLER_20
PdfAnnotation* pdfAnnotation = static_cast< PdfAnnotation* >(annotation);
m_page->removeAnnotation(pdfAnnotation->m_annotation);
pdfAnnotation->m_annotation = 0;
#else
Q_UNUSED(annotation);
#endif // HAS_POPPLER_20
}
QList< FormField* > PdfPage::formFields() const
{
LOCK_PAGE
QList< FormField* > formFields;
foreach(Poppler::FormField* formField, m_page->formFields())
{
if(!formField->isVisible() || formField->isReadOnly())
{
delete formField;
continue;
}
if(formField->type() == Poppler::FormField::FormText)
{
Poppler::FormFieldText* formFieldText = static_cast< Poppler::FormFieldText* >(formField);
if(formFieldText->textType() == Poppler::FormFieldText::Normal || formFieldText->textType() == Poppler::FormFieldText::Multiline)
{
formFields.append(new PdfFormField(m_mutex, formField));
continue;
}
}
else if(formField->type() == Poppler::FormField::FormChoice)
{
Poppler::FormFieldChoice* formFieldChoice = static_cast< Poppler::FormFieldChoice* >(formField);
if(formFieldChoice->choiceType() == Poppler::FormFieldChoice::ListBox || formFieldChoice->choiceType() == Poppler::FormFieldChoice::ComboBox)
{
formFields.append(new PdfFormField(m_mutex, formField));
continue;
}
}
else if(formField->type() == Poppler::FormField::FormButton)
{
Poppler::FormFieldButton* formFieldButton = static_cast< Poppler::FormFieldButton* >(formField);
if(formFieldButton->buttonType() == Poppler::FormFieldButton::CheckBox || formFieldButton->buttonType() == Poppler::FormFieldButton::Radio)
{
formFields.append(new PdfFormField(m_mutex, formField));
continue;
}
}
delete formField;
}
return formFields;
}
PdfDocument::PdfDocument(Poppler::Document* document) :
m_mutex(),
m_document(document)
{
}
PdfDocument::~PdfDocument()
{
delete m_document;
}
int PdfDocument::numberOfPages() const
{
LOCK_DOCUMENT
return m_document->numPages();
}
Page* PdfDocument::page(int index) const
{
LOCK_DOCUMENT
if(Poppler::Page* page = m_document->page(index))
{
return new PdfPage(&m_mutex, page);
}
return 0;
}
bool PdfDocument::isLocked() const
{
LOCK_DOCUMENT
return m_document->isLocked();
}
bool PdfDocument::unlock(const QString& password)
{
LOCK_DOCUMENT
// Poppler drops render hints and backend after unlocking so we need to restore them.
const Poppler::Document::RenderHints hints = m_document->renderHints();
const Poppler::Document::RenderBackend backend = m_document->renderBackend();
const bool ok = m_document->unlock(password.toLatin1(), password.toLatin1());
restoreRenderHint(m_document, hints, Poppler::Document::Antialiasing);
restoreRenderHint(m_document, hints, Poppler::Document::TextAntialiasing);
#ifdef HAS_POPPLER_14
restoreRenderHint(m_document, hints, Poppler::Document::TextHinting);
#endif // HAS_POPPLER_14
#ifdef HAS_POPPLER_18
restoreRenderHint(m_document, hints, Poppler::Document::TextSlightHinting);
#endif // HAS_POPPLER_18
#ifdef HAS_POPPLER_35
restoreRenderHint(m_document, hints, Poppler::Document::IgnorePaperColor);
#endif // HAS_POPPLER_35
#ifdef HAS_POPPLER_22
restoreRenderHint(m_document, hints, Poppler::Document::OverprintPreview);
#endif // HAS_POPPLER_22
#ifdef HAS_POPPLER_24
restoreRenderHint(m_document, hints, Poppler::Document::ThinLineSolid);
restoreRenderHint(m_document, hints, Poppler::Document::ThinLineShape);
#endif // HAS_POPPLER_24
m_document->setRenderBackend(backend);
return ok;
}
QStringList PdfDocument::saveFilter() const
{
return QStringList() << "Portable document format (*.pdf)";
}
bool PdfDocument::canSave() const
{
return true;
}
bool PdfDocument::save(const QString& filePath, bool withChanges) const
{
LOCK_DOCUMENT
QScopedPointer< Poppler::PDFConverter > pdfConverter(m_document->pdfConverter());
pdfConverter->setOutputFileName(filePath);
Poppler::PDFConverter::PDFOptions options = pdfConverter->pdfOptions();
if(withChanges)
{
options |= Poppler::PDFConverter::WithChanges;
}
pdfConverter->setPDFOptions(options);
return pdfConverter->convert();
}
bool PdfDocument::canBePrintedUsingCUPS() const
{
return true;
}
void PdfDocument::setPaperColor(const QColor& paperColor)
{
LOCK_DOCUMENT
m_document->setPaperColor(paperColor);
}
Outline PdfDocument::outline() const
{
Outline outline;
LOCK_DOCUMENT
QScopedPointer< QDomDocument > toc(m_document->toc());
if(toc)
{
outline = loadOutline(*toc, m_document);
}
return outline;
}
Properties PdfDocument::properties() const
{
Properties properties;
LOCK_DOCUMENT
foreach(const QString& key, m_document->infoKeys())
{
QString value = m_document->info(key);
if(value.startsWith("D:"))
{
value = m_document->date(key).toString();
}
properties.push_back(qMakePair(key, value));
}
int pdfMajorVersion = 1;
int pdfMinorVersion = 0;
m_document->getPdfVersion(&pdfMajorVersion, &pdfMinorVersion);
properties.push_back(qMakePair(tr("PDF version"), QString("%1.%2").arg(pdfMajorVersion).arg(pdfMinorVersion)));
properties.push_back(qMakePair(tr("Encrypted"), m_document->isEncrypted() ? tr("Yes") : tr("No")));
properties.push_back(qMakePair(tr("Linearized"), m_document->isLinearized() ? tr("Yes") : tr("No")));
return properties;
}
QAbstractItemModel* PdfDocument::fonts() const
{
LOCK_DOCUMENT
return new FontsModel(m_document->fonts());
}
bool PdfDocument::wantsContinuousMode() const
{
LOCK_DOCUMENT
const Poppler::Document::PageLayout pageLayout = m_document->pageLayout();
return pageLayout == Poppler::Document::OneColumn
|| pageLayout == Poppler::Document::TwoColumnLeft
|| pageLayout == Poppler::Document::TwoColumnRight;
}
bool PdfDocument::wantsSinglePageMode() const
{
LOCK_DOCUMENT
const Poppler::Document::PageLayout pageLayout = m_document->pageLayout();
return pageLayout == Poppler::Document::SinglePage
|| pageLayout == Poppler::Document::OneColumn;
}
bool PdfDocument::wantsTwoPagesMode() const
{
LOCK_DOCUMENT
const Poppler::Document::PageLayout pageLayout = m_document->pageLayout();
return pageLayout == Poppler::Document::TwoPageLeft
|| pageLayout == Poppler::Document::TwoColumnLeft;
}
bool PdfDocument::wantsTwoPagesWithCoverPageMode() const
{
LOCK_DOCUMENT
const Poppler::Document::PageLayout pageLayout = m_document->pageLayout();
return pageLayout == Poppler::Document::TwoPageRight
|| pageLayout == Poppler::Document::TwoColumnRight;
}
bool PdfDocument::wantsRightToLeftMode() const
{
#ifdef HAS_POPPLER_26
return m_document->textDirection() == Qt::RightToLeft;
#else
return false;
#endif // HAS_POPPLER_26
}
} // Model
PdfSettingsWidget::PdfSettingsWidget(QSettings* settings, QWidget* parent) : SettingsWidget(parent),
m_settings(settings)
{
m_layout = new QFormLayout(this);
// antialiasing
m_antialiasingCheckBox = new QCheckBox(this);
m_antialiasingCheckBox->setChecked(m_settings->value("antialiasing", Defaults::antialiasing).toBool());
m_layout->addRow(tr("Antialiasing:"), m_antialiasingCheckBox);
// text antialising
m_textAntialiasingCheckBox = new QCheckBox(this);
m_textAntialiasingCheckBox->setChecked(m_settings->value("textAntialiasing", Defaults::textAntialiasing).toBool());
m_layout->addRow(tr("Text antialiasing:"), m_textAntialiasingCheckBox);
// text hinting
#ifdef HAS_POPPLER_18
m_textHintingComboBox = new QComboBox(this);
m_textHintingComboBox->addItem(tr("None"));
m_textHintingComboBox->addItem(tr("Full"));
m_textHintingComboBox->addItem(tr("Reduced"));
m_textHintingComboBox->setCurrentIndex(m_settings->value("textHinting", Defaults::textHinting).toInt());
m_layout->addRow(tr("Text hinting:"), m_textHintingComboBox);
#else
m_textHintingCheckBox = new QCheckBox(this);
m_textHintingCheckBox->setChecked(m_settings->value("textHinting", Defaults::textHinting).toBool());
m_layout->addRow(tr("Text hinting:"), m_textHintingCheckBox);
#endif // HAS_POPPLER_18
#ifdef HAS_POPPLER_35
m_ignorePaperColorCheckBox = new QCheckBox(this);
m_ignorePaperColorCheckBox->setChecked(m_settings->value("ignorePaperColor", Defaults::ignorePaperColor).toBool());
m_layout->addRow(tr("Ignore paper color:"), m_ignorePaperColorCheckBox);
#endif // HAS_POPPLER_35
#ifdef HAS_POPPLER_22
// overprint preview
m_overprintPreviewCheckBox = new QCheckBox(this);
m_overprintPreviewCheckBox->setChecked(m_settings->value("overprintPreview", Defaults::overprintPreview).toBool());
m_layout->addRow(tr("Overprint preview:"), m_overprintPreviewCheckBox);
#endif // HAS_POPPLER_22
#ifdef HAS_POPPLER_24
m_thinLineModeComboBox = new QComboBox(this);
m_thinLineModeComboBox->addItem(tr("None"));
m_thinLineModeComboBox->addItem(tr("Solid"));
m_thinLineModeComboBox->addItem(tr("Shaped"));
m_thinLineModeComboBox->setCurrentIndex(m_settings->value("thinLineMode", Defaults::thinLineMode).toInt());
m_layout->addRow(tr("Thin line mode:"), m_thinLineModeComboBox);
#endif // HAS_POPPLER_24
m_backendComboBox = new QComboBox(this);
m_backendComboBox->addItem(tr("Splash"));
m_backendComboBox->addItem(tr("Arthur"));
m_backendComboBox->setCurrentIndex(m_settings->value("backend", Defaults::backend).toInt());
m_layout->addRow(tr("Backend:"), m_backendComboBox);
}
void PdfSettingsWidget::accept()
{
m_settings->setValue("antialiasing", m_antialiasingCheckBox->isChecked());
m_settings->setValue("textAntialiasing", m_textAntialiasingCheckBox->isChecked());
#ifdef HAS_POPPLER_18
m_settings->setValue("textHinting", m_textHintingComboBox->currentIndex());
#else
m_settings->setValue("textHinting", m_textHintingCheckBox->isChecked());
#endif // HAS_POPPLER_18
#ifdef HAS_POPPLER_35
m_settings->setValue("ignorePaperColor", m_ignorePaperColorCheckBox->isChecked());
#endif // HAS_POPPLER_35
#ifdef HAS_POPPLER_22
m_settings->setValue("overprintPreview", m_overprintPreviewCheckBox->isChecked());
#endif // HAS_POPPLER_22
#ifdef HAS_POPPLER_24
m_settings->setValue("thinLineMode", m_thinLineModeComboBox->currentIndex());
#endif // HAS_POPPLER_24
m_settings->setValue("backend", m_backendComboBox->currentIndex());
}
void PdfSettingsWidget::reset()
{
m_antialiasingCheckBox->setChecked(Defaults::antialiasing);
m_textAntialiasingCheckBox->setChecked(Defaults::textAntialiasing);
#ifdef HAS_POPPLER_18
m_textHintingComboBox->setCurrentIndex(Defaults::textHinting);
#else
m_textHintingCheckBox->setChecked(Defaults::textHinting);
#endif // HAS_POPPLER_18
#ifdef HAS_POPPLER_35
m_ignorePaperColorCheckBox->setChecked(Defaults::ignorePaperColor);
#endif // HAS_POPPLER_35
#ifdef HAS_POPPLER_22
m_overprintPreviewCheckBox->setChecked(Defaults::overprintPreview);
#endif // HAS_POPPLER_22
#ifdef HAS_POPPLER_24
m_thinLineModeComboBox->setCurrentIndex(Defaults::thinLineMode);
#endif // HAS_POPPLER_24
m_backendComboBox->setCurrentIndex(Defaults::backend);
}
PdfPlugin::PdfPlugin(QObject* parent) : QObject(parent)
{
setObjectName("PdfPlugin");
m_settings = new QSettings("qpdfview", "pdf-plugin", this);
}
Model::Document* PdfPlugin::loadDocument(const QString& filePath) const
{
if(Poppler::Document* document = Poppler::Document::load(filePath))
{
document->setRenderHint(Poppler::Document::Antialiasing, m_settings->value("antialiasing", Defaults::antialiasing).toBool());
document->setRenderHint(Poppler::Document::TextAntialiasing, m_settings->value("textAntialiasing", Defaults::textAntialiasing).toBool());
#if defined(HAS_POPPLER_18)
switch(m_settings->value("textHinting", Defaults::textHinting).toInt())
{
default:
case 0:
document->setRenderHint(Poppler::Document::TextHinting, false);
break;
case 1:
document->setRenderHint(Poppler::Document::TextHinting, true);
document->setRenderHint(Poppler::Document::TextSlightHinting, false);
break;
case 2:
document->setRenderHint(Poppler::Document::TextHinting, true);
document->setRenderHint(Poppler::Document::TextSlightHinting, true);
break;
}
#elif defined(HAS_POPPLER_14)
document->setRenderHint(Poppler::Document::TextHinting, m_settings->value("textHinting", Defaults::textHinting).toBool());
#endif // HAS_POPPLER_18 HAS_POPPLER_14
#ifdef HAS_POPPLER_35
document->setRenderHint(Poppler::Document::IgnorePaperColor, m_settings->value("ignorePaperColor", Defaults::ignorePaperColor).toBool());
#endif // HAS_POPPLER_35
#ifdef HAS_POPPLER_22
document->setRenderHint(Poppler::Document::OverprintPreview, m_settings->value("overprintPreview", Defaults::overprintPreview).toBool());
#endif // HAS_POPPLER_22
#ifdef HAS_POPPLER_24
switch(m_settings->value("thinLineMode", Defaults::thinLineMode).toInt())
{
default:
case 0:
document->setRenderHint(Poppler::Document::ThinLineSolid, false);
document->setRenderHint(Poppler::Document::ThinLineShape, false);
break;
case 1:
document->setRenderHint(Poppler::Document::ThinLineSolid, true);
document->setRenderHint(Poppler::Document::ThinLineShape, false);
break;
case 2:
document->setRenderHint(Poppler::Document::ThinLineSolid, false);
document->setRenderHint(Poppler::Document::ThinLineShape, true);
break;
}
#endif // HAS_POPPLER_24
switch(m_settings->value("backend", Defaults::backend).toInt())
{
default:
case 0:
document->setRenderBackend(Poppler::Document::SplashBackend);
break;
case 1:
document->setRenderBackend(Poppler::Document::ArthurBackend);
break;
}
return new Model::PdfDocument(document);
}
return 0;
}
SettingsWidget* PdfPlugin::createSettingsWidget(QWidget* parent) const
{
return new PdfSettingsWidget(m_settings, parent);
}
} // qpdfview
#if QT_VERSION < QT_VERSION_CHECK(5,0,0)
Q_EXPORT_PLUGIN2(qpdfview_pdf, qpdfview::PdfPlugin)
#endif // QT_VERSION