From: Stefan Bund Date: Thu, 21 Oct 2010 11:51:31 +0000 (+0200) Subject: Separate Viewer from MainWindow and implement PDF embedding X-Git-Url: http://g0dil.de/git?p=pykit.git;a=commitdiff_plain;h=c39edbfdec96e88bdafa0b771939924f73799e84 Separate Viewer from MainWindow and implement PDF embedding --- diff --git a/MainWindow.cc b/MainWindow.cc index 59913c7..543752d 100644 --- a/MainWindow.cc +++ b/MainWindow.cc @@ -10,25 +10,17 @@ //#include "MainWindow.ih" // Custom includes -#include -#include "Publisher.hh" +#include "Viewer.hh" //#include "MainWindow.mpp" #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// -prefix_ pykit::MainWindow::MainWindow(QUrl const & url, Publisher * publisher, - QWidget * parent) - : QMainWindow (parent) +prefix_ pykit::MainWindow::MainWindow(QUrl const & url, Publisher * publisher, + QWidget * parent) + : QMainWindow (parent) { - //QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true); - - QWebView *view = new QWebView; - view->page()->setNetworkAccessManager( - new InternalNetworkAccessManager(view->page()->networkAccessManager(), view, publisher)); - - view->load(url); - + Viewer * view = new Viewer(url, publisher, this); setCentralWidget(view); } diff --git a/PDFWidget.cc b/PDFWidget.cc new file mode 100644 index 0000000..76c559d --- /dev/null +++ b/PDFWidget.cc @@ -0,0 +1,73 @@ +// $Id$ +// +// Copyright (C) 2010 +// Stefan Bund + +/** \file + \brief PDFWidget non-inline non-template implementation */ + +#include "PDFWidget.hh" +//#include "PDFWidget.ih" + +// Custom includes +#include +#include +#include + +//#include "PDFWidget.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +prefix_ pykit::PDFWidget::PDFWidget(QNetworkAccessManager * manager, QWidget * parent) + : QLabel(parent), manager_ (manager), currentPage_ (0) +{} + +prefix_ pykit::PDFWidget::PDFWidget(QString const & document, QNetworkAccessManager * manager, + QWidget * parent) + : QLabel(parent), manager_ (manager), currentPage_ (0) +{ + document_.reset(Poppler::Document::load(document)); + showPage(); +} + +prefix_ void pykit::PDFWidget::load(QUrl const & url) +{ + QNetworkRequest request (url); + QNetworkReply * reply (manager_->get(request)); + connect(reply, SIGNAL(finished()), this, SLOT(netLoadDocument())); +} + +prefix_ void pykit::PDFWidget::netLoadDocument() +{ + QNetworkReply * reply = static_cast(sender()); + if (reply->error() != QNetworkReply::NoError) + return; + QByteArray data (reply->read(reply->size())); + document_.reset(Poppler::Document::loadFromData(data)); + showPage(); + reply->deleteLater(); +} + +prefix_ void pykit::PDFWidget::showPage() +{ + if (! document_) + return; + QImage image (document_->page(currentPage_)->renderToImage( + physicalDpiX(), physicalDpiY())); + setPixmap(QPixmap::fromImage(image)); +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "PDFWidget.mpp" + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "j32" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -U" +// End: diff --git a/PDFWidget.hh b/PDFWidget.hh new file mode 100644 index 0000000..a6212ff --- /dev/null +++ b/PDFWidget.hh @@ -0,0 +1,64 @@ +// $Id$ +// +// Copyright (C) 2010 +// Stefan Bund + +/** \file + \brief PDFWidget public header */ + +#ifndef HH_PyKit_PDFWidget_ +#define HH_PyKit_PDFWidget_ 1 + +// Custom includes +#include +#include +#include +#include +#include +#include +#include + +//#include "PDFWidget.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace pykit { + + class PDFWidget : public QLabel + { + Q_OBJECT; + public: + explicit PDFWidget(QNetworkAccessManager * manager, QWidget * parent = 0); + PDFWidget(QString const & document, QNetworkAccessManager * manager, + QWidget * parent = 0); + + void load(QUrl const & url); + + private slots: + void netLoadDocument(); + + private: + void showPage(); + + QNetworkAccessManager * manager_; + boost::scoped_ptr document_; + int currentPage_; + }; + +} + +///////////////////////////////hh.e//////////////////////////////////////// +//#include "PDFWidget.cci" +//#include "PDFWidget.ct" +//#include "PDFWidget.cti" +#endif + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "j32" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -U" +// End: diff --git a/Publisher.cc b/Publisher.cc index 02c3521..7176b7c 100644 --- a/Publisher.cc +++ b/Publisher.cc @@ -54,8 +54,8 @@ namespace detail { void clearResponse(); protected: - qint64 readData(char * data, qint64 maxSize); - qint64 writeData(char const * data, qint64 maxSize); + virtual qint64 readData(char * data, qint64 maxSize); + virtual qint64 writeData(char const * data, qint64 maxSize); signals: void initSignal(); @@ -160,7 +160,7 @@ prefix_ void pykit::detail::InternalServerReply::clearResponse() prefix_ void pykit::Request::write(std::string const & data) { - reply_.write(data.c_str()); + reply_.write(QByteArray(data.data(),data.size())); } prefix_ void pykit::Request::reset() diff --git a/Publisher.hh b/Publisher.hh index 5e95625..2fd4cba 100644 --- a/Publisher.hh +++ b/Publisher.hh @@ -14,6 +14,7 @@ #include #include #include +#include //#include "Publisher.mpp" ///////////////////////////////hh.p//////////////////////////////////////// @@ -42,6 +43,7 @@ namespace pykit { }; class Publisher + : boost::noncopyable { public: virtual ~Publisher() {} diff --git a/PythonPublisher.cc b/PythonPublisher.cc index c75fc88..56d7bc4 100644 --- a/PythonPublisher.cc +++ b/PythonPublisher.cc @@ -10,6 +10,8 @@ //#include "PythonPublisher.ih" // Custom includes +#include +#include #include "Publisher.hh" //#include "PythonPublisher.mpp" @@ -18,6 +20,15 @@ namespace py = boost::python; +struct pykit::PythonPublisher::Impl +{ + boost::python::dict mainNamespace; + Publisher * pythonPublisher; +}; + +#define PYTHON_PREPARE_IMPORT(module) \ + PyImport_AppendInittab(const_cast(#module), init ## module) + namespace { struct PublisherPyWrapper @@ -34,7 +45,7 @@ namespace { static PyObject * convert(QString const & s) { std::wstring ws (s.toStdWString()); - return PyUnicode_FromWideChar(ws.c_str(), ws.length()); + return PyUnicode_FromWideChar(ws.data(), ws.length()); } }; @@ -88,10 +99,11 @@ namespace { static void construct(PyObject * o, py::converter::rvalue_from_python_stage1_data * data) { + unsigned length (PyString_Size(o)); const char * value (PyString_AsString(o)); void * storage (((py::converter::rvalue_from_python_storage*) data)->storage.bytes); - new (storage) QByteArray(value); + new (storage) QByteArray(value,length); data->convertible = storage; } @@ -420,22 +432,32 @@ BOOST_PYTHON_MODULE(_pykit) } prefix_ pykit::PythonPublisher::PythonPublisher(std::string initPy) + : impl_ (new Impl) { - PYTHON_PREPARE_IMPORT(_pykit); - PYTHON_PREPARE_IMPORT(_qt); - Py_Initialize(); - py::object mainModule_ = py::import("__main__"); - mainNamespace_ = py::extract(mainModule_.attr("__dict__")); - mainNamespace_["__file__"] = py::str(initPy.c_str()); - py::object ignored ( - py::exec_file(initPy.c_str(), mainNamespace_, mainNamespace_)); - pythonPublisher_ = py::extract(mainNamespace_["publisher"]); + try { + PYTHON_PREPARE_IMPORT(_pykit); + PYTHON_PREPARE_IMPORT(_qt); + Py_Initialize(); + py::object mainModule_ = py::import("__main__"); + impl_->mainNamespace = py::extract(mainModule_.attr("__dict__")); + impl_->mainNamespace["__file__"] = py::str(initPy.c_str()); + py::object ignored ( + py::exec_file(initPy.c_str(), impl_->mainNamespace, impl_->mainNamespace)); + impl_->pythonPublisher = py::extract(impl_->mainNamespace["publisher"]); + } + catch (boost::python::error_already_set & ex) { + PyErr_Print(); + throw; + } } +prefix_ pykit::PythonPublisher::~PythonPublisher() +{} + prefix_ void pykit::PythonPublisher::publish(Request & request) { try { - pythonPublisher_->publish(request); + impl_->pythonPublisher->publish(request); } catch (py::error_already_set & ex) { PyErr_Print(); diff --git a/PythonPublisher.hh b/PythonPublisher.hh index b00c983..b6b6a5e 100644 --- a/PythonPublisher.hh +++ b/PythonPublisher.hh @@ -10,7 +10,7 @@ #define HH_PyKit_PythonPublisher_ 1 // Custom includes -#include +#include #include "Publisher.hh" //#include "PythonPublisher.mpp" @@ -22,18 +22,16 @@ namespace pykit { : public Publisher { public: - PythonPublisher(std::string initPy); + explicit PythonPublisher(std::string initPy); + ~PythonPublisher(); void publish(Request & request); private: - boost::python::dict mainNamespace_; - Publisher * pythonPublisher_; + struct Impl; + boost::scoped_ptr impl_; }; -# define PYTHON_PREPARE_IMPORT(module) \ - PyImport_AppendInittab(const_cast(#module), init ## module) - } ///////////////////////////////hh.e//////////////////////////////////////// diff --git a/SConscript b/SConscript index 56a2e28..2614eb2 100644 --- a/SConscript +++ b/SConscript @@ -9,12 +9,9 @@ env.Tool('qt4', [ os.path.join('site_scons','qtscons') ]) env.EnableQt4Modules([ 'QtWebKit', 'QtNetwork', 'QtSvg', 'QtXml', 'QtGui', 'QtCore' ]) env.Append( - CXXFLAGS = [ '-Wall', '-Wextra' ], - CPPPATH = [ '$LIBPYTHONINCLUDES' ], - LIBS = [ '$LIBBOOSTPYTHON', '$LIBPYTHON' ] + CXXFLAGS = [ '-Wall', '-Wextra' ], + LIBS = [ '$BOOSTPYLIBS', '$POPPLERLIBS' ], ) -sources = env.Qt4Glob() - -pykit = env.Program('pykit', sources) +pykit = env.Program('pykit', env.Qt4Glob()) env.Default(pykit) diff --git a/SConstruct b/SConstruct index beeaf1b..a5b3878 100644 --- a/SConstruct +++ b/SConstruct @@ -5,17 +5,12 @@ import os env = Environment(ENV = os.environ) env.SetDefault( - PYTHON = 'python', - LIBPYTHON = 'python$PYTHONVERSION', - LIBPYTHONINCLUDES = '/usr/include/python$PYTHONVERSION', - LIBBOOSTPYTHON = 'boost_python' + BOOSTPYLIBS = [ 'boost_python' ], + POPPLERLIBS = [ 'poppler', 'poppler-qt4' ], ) -env.SetDefault( - PYTHONVERSION = os.popen(env.subst( - """$PYTHON -c 'import sys; print".".join(map(str,sys.version_info[:2]))'""")).read(), -) +env.MergeFlags('!python-config --cflags') +env.MergeFlags('!python-config --ldflags') Export('env') - env.SConscript("SConscript") diff --git a/Viewer.cc b/Viewer.cc new file mode 100644 index 0000000..abb1b2f --- /dev/null +++ b/Viewer.cc @@ -0,0 +1,106 @@ +// $Id$ +// +// Copyright (C) 2010 +// Stefan Bund + +/** \file + \brief Viewer non-inline non-template implementation */ + +#include "Viewer.hh" +//#include "Viewer.ih" + +// Custom includes +#include +#include +#include "Publisher.hh" +#include "PDFWidget.hh" + +//#include "Viewer.mpp" +#define prefix_ +///////////////////////////////cc.p//////////////////////////////////////// + +namespace { + + class PDFWebPluginFactory + : public QWebPluginFactory + { + public: + PDFWebPluginFactory(QNetworkAccessManager * manager, QObject * parent = 0); + + QObject * create(QString const & mimeType, QUrl const & url, + QStringList const & argumentNames, QStringList const & argumentValues) + const; + QList plugins() const; + + private: + QNetworkAccessManager * manager_; + }; + +} + +prefix_ PDFWebPluginFactory::PDFWebPluginFactory(QNetworkAccessManager * manager, + QObject * parent) + : QWebPluginFactory(parent), manager_ (manager) +{} + +prefix_ QObject * PDFWebPluginFactory::create(QString const & mimeType, QUrl const & url, + QStringList const & /* argumentNames */, + QStringList const & /* argumentValues */) + const +{ + if (mimeType == "application/x-pdf") { + pykit::PDFWidget * plugin = new pykit::PDFWidget(manager_); + plugin->load(url); + return plugin; + } + return 0; +} + +prefix_ QList PDFWebPluginFactory::plugins() + const +{ + QList plugins; + + { + QWebPluginFactory::Plugin plugin; + plugin.name = "PDF viewer"; + plugin.description = "View PDF files"; + { + QWebPluginFactory::MimeType mimeType; + mimeType.name = "application/x-pdf"; + mimeType.description = "PDF file"; + plugin.mimeTypes += mimeType; + } + plugins += plugin; + } + + return plugins; +} + +/////////////////////////////////////////////////////////////////////////// +// pykit::Viewer + +prefix_ pykit::Viewer::Viewer(QUrl const & url, Publisher * publisher, QWidget * parent) + : QWebView (parent) +{ + QWebSettings::globalSettings()->setAttribute(QWebSettings::PluginsEnabled, true); + page()->setNetworkAccessManager( + new InternalNetworkAccessManager(page()->networkAccessManager(), this, publisher)); + page()->setPluginFactory(new PDFWebPluginFactory (page()->networkAccessManager(), this)); + load(url); +} + +///////////////////////////////cc.e//////////////////////////////////////// +#undef prefix_ +//#include "Viewer.mpp" + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "j32" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -U" +// End: diff --git a/Viewer.hh b/Viewer.hh new file mode 100644 index 0000000..21ba371 --- /dev/null +++ b/Viewer.hh @@ -0,0 +1,48 @@ +// $Id$ +// +// Copyright (C) 2010 +// Stefan Bund + +/** \file + \brief Viewer public header */ + +#ifndef HH_PyKit_Viewer_ +#define HH_PyKit_Viewer_ 1 + +// Custom includes +#include +#include + +//#include "Viewer.mpp" +///////////////////////////////hh.p//////////////////////////////////////// + +namespace pykit { + + class Publisher; + + class Viewer + : public QWebView + { + Q_OBJECT; + public: + Viewer(QUrl const & url, Publisher * publisher, QWidget * parent = 0); + }; + +} + +///////////////////////////////hh.e//////////////////////////////////////// +//#include "Viewer.cci" +//#include "Viewer.ct" +//#include "Viewer.cti" +#endif + + +// Local Variables: +// mode: c++ +// fill-column: 100 +// comment-column: 40 +// c-file-style: "j32" +// indent-tabs-mode: nil +// ispell-local-dictionary: "american" +// compile-command: "scons -U" +// End: diff --git a/main.cc b/main.cc index 84a675f..fcebd20 100644 --- a/main.cc +++ b/main.cc @@ -15,7 +15,6 @@ #include #include #include -#include #include #include "MainWindow.hh" #include "PythonPublisher.hh" @@ -68,10 +67,6 @@ int main(int argc, char *argv[]) return app.exec(); } - catch (boost::python::error_already_set & ex) { - PyErr_Print(); - throw; - } catch (std::exception & ex) { std::cerr << "Exception:\n" << ex.what() << "\n"; throw; diff --git a/project.el b/project.el new file mode 100644 index 0000000..ae81838 --- /dev/null +++ b/project.el @@ -0,0 +1,59 @@ +;; Configuration file for cc-ide.el (Emacs C++ IDE extension, see http://g0dil.de) + +(defun check-namespace-indent (arg) + (save-excursion + (back-to-indentation) + (if (and (looking-at "namespace") + (looking-at ".*{") + (not (looking-at ".*}"))) + [0] '+))) + +(defconst j32-c-style + '((c-basic-offset . 4) + (c-access-key . "\\(public\\|protected\\|private\\|signals\\|public\\s-*slots\\|protected\\s-*slots\\|private\\s-slots\\)\\s-*:") + (c-backslash-column . 98) + (c-cleanup-list . (empty-defun-braces + defun-close-semi + list-close-comma + scope-operator)) + (c-hanging-braces-alist . ((namespace-open after) + (namespace-close before after) + (brace-list-open) + (brace-entry-open) + (substatement-open after) + (block-close . c-snug-do-while) + (extern-lang-open after) + (inexpr-class-open after) + (inexpr-class-close before))) + (c-offsets-alist . ((namespace-open . [0]) + (namespace-close . [0]) + (innamespace . check-namespace-indent) + (statement-block-intro . +) + (substatement-open . 0) + (label . 0) + (statement-cont . +))) )) + +(c-add-style "j32" j32-c-style) + +(set (make-local-variable 'ccide-file-vars) + '((fill-column . 100) + (comment-column . 40) + (c-file-style . "j32") + (indent-tabs-mode . nil) + (ispell-local-dictionary . "american") + (compile-command . "scons -U"))) + +(set (make-local-variable 'ccide-project-name) "PyKit") + +(let ((local-conf (ccide-project-search-upwards "project-local.el"))) + (if local-conf + (load-file local-conf))) + +(setq indent-tabs-mode nil) ;; needed since whitespace-mode caches this value ... +(whitespace-mode 1) + +(message "Loaded project settings.") + +;; Local Variables: +;; indent-tabs-mode: nil +;; End: