Skip to content

Commit

Permalink
Implement BackendInterface to allow a choice of backends at run-time
Browse files Browse the repository at this point in the history
 - New backends should implement BackendInterface
 - Use the interfaces to create new documents by means of the newDocument() method
  • Loading branch information
stloeffler committed Sep 9, 2012
1 parent 6e0c0d6 commit d5c970f
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 0 deletions.
8 changes: 8 additions & 0 deletions PDFViewer.cpp
Expand Up @@ -6,6 +6,14 @@ PDFViewer::PDFViewer(const QString pdf_doc, QWidget *parent, Qt::WindowFlags fla
QtPDF::PDFDocumentWidget *docWidget = new QtPDF::PDFDocumentWidget(this);
connect(this, SIGNAL(switchInterfaceLocale(QLocale)), docWidget, SLOT(switchInterfaceLocale(QLocale)));

#ifdef USE_MUPDF
docWidget->setDefaultBackend(QString::fromAscii("mupdf"));
#elif USE_POPPLER
docWidget->setDefaultBackend(QString::fromAscii("poppler-qt4"));
#else
#error At least one backend is required
#endif

if (!pdf_doc.isEmpty() && docWidget)
docWidget->load(pdf_doc);
docWidget->goFirst();
Expand Down
12 changes: 12 additions & 0 deletions src/PDFBackend.h
Expand Up @@ -612,8 +612,20 @@ class Page

} // namespace Backend

class BackendInterface : public QObject
{
Q_OBJECT
public:
virtual ~BackendInterface() { }
virtual QSharedPointer<Backend::Document> newDocument(const QString & fileName) = 0;
virtual QString name() const = 0;
virtual bool canHandleFile(const QString & fileName) = 0;
};

} // namespace QtPDF

Q_DECLARE_INTERFACE(QtPDF::BackendInterface, "org.tug.QtPDF/1.0")

// Backend Implementations
// =======================
// These provide library-specific concrete impelemntations of the abstract base
Expand Down
51 changes: 51 additions & 0 deletions src/PDFDocumentWidget.cpp
Expand Up @@ -18,17 +18,29 @@ namespace QtPDF {
PDFDocumentWidget::PDFDocumentWidget(QWidget * parent /* = NULL */)
: PDFDocumentView(parent)
{
#ifdef USE_MUPDF
_backends.append(new MuPDFBackend());
#endif
#ifdef USE_POPPLER
_backends.append(new PopplerQt4Backend());
#endif
}

PDFDocumentWidget::~PDFDocumentWidget()
{
foreach(BackendInterface * bi, _backends) {
if (!bi)
continue;
bi->deleteLater();
}
}

// Loads the file specified by filename. If this succeeds, the new file is
// displayed and true is returned. Otherwise, the view is not altered and false
// is returned
bool PDFDocumentWidget::load(const QString &filename)
{
/*
// *TODO*: If more than one backend is available, maybe let users set their
// preferred one
#ifdef USE_MUPDF
Expand All @@ -38,6 +50,14 @@ bool PDFDocumentWidget::load(const QString &filename)
#else
#error Either the Poppler or the MuPDF backend is required
#endif
*/
QSharedPointer<QtPDF::Backend::Document> a_pdf_doc;
foreach(BackendInterface * bi, _backends) {
if (bi && bi->canHandleFile(filename))
a_pdf_doc = bi->newDocument(filename);
if (a_pdf_doc)
break;
}

if (!a_pdf_doc || !a_pdf_doc->isValid())
return false;
Expand All @@ -52,4 +72,35 @@ bool PDFDocumentWidget::load(const QString &filename)
return true;
}

QStringList PDFDocumentWidget::backends() const
{
QStringList retVal;
foreach (BackendInterface * bi, _backends) {
if (bi)
continue;
retVal << bi->name();
}
return retVal;
}

QString PDFDocumentWidget::defaultBackend() const
{
if (_backends.size() == 0)
return QString();
return _backends[0]->name();
}

void PDFDocumentWidget::setDefaultBackend(const QString & backend)
{
int i;
for (i = 0; i < _backends.size(); ++i) {
if (_backends[i]->name() == backend)
break;
}
if (i < _backends.size()) {
_backends.move(i, 0);
}
}


} // namespace QtPDF
5 changes: 5 additions & 0 deletions src/PDFDocumentWidget.h
Expand Up @@ -30,10 +30,15 @@ class PDFDocumentWidget : public PDFDocumentView
bool watchForDocumentChangesOnDisk() const { return _scene->watchForDocumentChangesOnDisk(); }
void setWatchForDocumentChangesOnDisk(const bool doWatch = true) { _scene->setWatchForDocumentChangesOnDisk(doWatch); }

QStringList backends() const;
QString defaultBackend() const;
void setDefaultBackend(const QString & backend);

// *TODO*: Possibly add some way to describe/choose/change the PDF backend used

protected:
QSharedPointer<QtPDF::PDFDocumentScene> _scene;
QList<BackendInterface*> _backends;
};

} // namespace QtPDF
Expand Down
18 changes: 18 additions & 0 deletions src/backends/MuPDFBackend.h
Expand Up @@ -21,6 +21,8 @@
#ifndef MuPDFBackend_H
#define MuPDFBackend_H

#include "PDFBackend.h"

extern "C"
{
#include <fitz.h>
Expand Down Expand Up @@ -127,6 +129,22 @@ class Page: public Backend::Page

} // namespace Backend

class MuPDFBackend : public BackendInterface
{
Q_OBJECT
Q_INTERFACES(QtPDF::BackendInterface)
public:
MuPDFBackend() { }
virtual ~MuPDFBackend() { }

virtual QSharedPointer<Backend::Document> newDocument(const QString & fileName) {
return QSharedPointer<Backend::Document>(new Backend::MuPDF::Document(fileName));
}

virtual QString name() const { return QString::fromAscii("mupdf"); }
virtual bool canHandleFile(const QString & fileName) { return QFileInfo(fileName).suffix() == QString::fromAscii("pdf"); }
};

} // namespace QtPDF

#endif // End header guard
Expand Down
17 changes: 17 additions & 0 deletions src/backends/PopplerBackend.h
Expand Up @@ -21,6 +21,7 @@
#ifndef PopplerBackend_H
#define PopplerBackend_H

#include "PDFBackend.h"
#include <poppler/qt4/poppler-qt4.h>

namespace QtPDF {
Expand Down Expand Up @@ -110,6 +111,22 @@ class Page: public Backend::Page

} // namespace Backend

class PopplerQt4Backend : public BackendInterface
{
Q_OBJECT
Q_INTERFACES(QtPDF::BackendInterface)
public:
PopplerQt4Backend() { }
virtual ~PopplerQt4Backend() { }

virtual QSharedPointer<Backend::Document> newDocument(const QString & fileName) {
return QSharedPointer<Backend::Document>(new Backend::Poppler::Document(fileName));
}

virtual QString name() const { return QString::fromAscii("poppler-qt4"); }
virtual bool canHandleFile(const QString & fileName) { return QFileInfo(fileName).suffix() == QString::fromAscii("pdf"); }
};

} // namespace QtPDF

#endif // End header guard
Expand Down

0 comments on commit d5c970f

Please sign in to comment.