initial release
Stefan Bund [Wed, 20 Oct 2010 10:54:47 +0000 (12:54 +0200)]
12 files changed:
.gitignore [new file with mode: 0644]
MainWindow.cc [new file with mode: 0644]
MainWindow.hh [new file with mode: 0644]
Publisher.cc [new file with mode: 0644]
Publisher.hh [new file with mode: 0644]
PythonPublisher.cc [new file with mode: 0644]
PythonPublisher.hh [new file with mode: 0644]
SConscript [new file with mode: 0644]
SConstruct [new file with mode: 0644]
init.py [new file with mode: 0644]
main.cc [new file with mode: 0644]
pykit.ini [new file with mode: 0644]

diff --git a/.gitignore b/.gitignore
new file mode 100644 (file)
index 0000000..3f1142b
--- /dev/null
@@ -0,0 +1,6 @@
+*.o
+*~
+moc_*
+.sconsign*
+*.moc
+/pykit
diff --git a/MainWindow.cc b/MainWindow.cc
new file mode 100644 (file)
index 0000000..59913c7
--- /dev/null
@@ -0,0 +1,48 @@
+// $Id$
+//
+// Copyright (C) 2010
+//     Stefan Bund <info@j32.de>
+
+/** \file
+    \brief MainWindow non-inline non-template implementation */
+
+#include "MainWindow.hh"
+//#include "MainWindow.ih"
+
+// Custom includes
+#include <QWebView>
+#include "Publisher.hh"
+
+//#include "MainWindow.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+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);
+
+    setCentralWidget(view);
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "MainWindow.mpp"
+
+\f
+// 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/MainWindow.hh b/MainWindow.hh
new file mode 100644 (file)
index 0000000..86baff4
--- /dev/null
@@ -0,0 +1,46 @@
+// $Id$
+//
+// Copyright (C) 2010
+//     Stefan Bund <info@j32.de>
+
+/** \file
+    \brief MainWindow public header */
+
+#ifndef HH_PyKit_MainWindow_
+#define HH_PyKit_MainWindow_ 1
+
+// Custom includes
+#include <QMainWindow>
+#include <QUrl>
+
+//#include "MainWindow.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace pykit {
+
+    class Publisher;
+
+    class MainWindow : public QMainWindow
+    {
+        Q_OBJECT;
+    public:
+        MainWindow(QUrl const & url, Publisher * publisher, QWidget * parent = 0);
+    };
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "MainWindow.cci"
+//#include "MainWindow.ct"
+//#include "MainWindow.cti"
+#endif
+
+\f
+// 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
new file mode 100644 (file)
index 0000000..02c3521
--- /dev/null
@@ -0,0 +1,231 @@
+// $Id$
+//
+// Copyright (C) 2010
+
+/** \file
+    \brief InternalNetworkAccessManager non-inline non-template implementation */
+
+#include "Publisher.hh"
+//#include "Publisher.ih"
+
+// Custom includes
+#include <iostream>
+#include <QNetworkProxy>
+#include <QVariant>
+#include "Publisher.hh"
+#include <boost/python.hpp>
+
+//#include "Publisher.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+///////////////////////////////////////////////////////////////////////////
+// pykit::detail::InternalServerReply
+
+namespace pykit {
+namespace detail {
+
+    class InternalServerReply
+        : public QNetworkReply
+    {
+        Q_OBJECT;
+    public:
+        InternalServerReply(QNetworkAccessManager::Operation operation,
+                            QNetworkRequest const & networkRequest,
+                            Publisher * publisher);
+
+        // Forwarded to buffer
+        virtual bool atEnd() const;
+        virtual qint64 bytesAvailable() const;
+        virtual qint64 bytesToWrite() const;
+        virtual bool canReadLine() const;
+        virtual bool isSequential() const;
+        virtual qint64 pos() const;
+        virtual bool reset();
+        virtual bool seek(qint64 pos);
+        virtual qint64 size() const;
+        virtual bool waitForBytesWritten(int msecs);
+        virtual bool waitForReadyRead(int msecs);
+
+        virtual void abort();
+
+        using QNetworkReply::setHeader;
+
+        void clearResponse();
+
+    protected:
+        qint64 readData(char * data, qint64 maxSize);
+        qint64 writeData(char const * data, qint64 maxSize);
+
+    signals:
+        void initSignal();
+
+    private slots:
+        void initSlot();
+
+    private:
+        QBuffer buffer_;
+    };
+
+}}
+
+prefix_ pykit::detail::InternalServerReply::
+InternalServerReply(QNetworkAccessManager::Operation operation,
+                    QNetworkRequest const & networkRequest, Publisher * publisher)
+{
+    setRequest(networkRequest);
+    setOperation(operation);
+    setUrl(networkRequest.url());
+    open(ReadWrite | Unbuffered);
+    buffer_.open(ReadWrite | Unbuffered);
+
+    Request request (*this);
+    publisher->publish(request);
+
+    seek(0);
+    setHeader(QNetworkRequest::ContentLengthHeader, QVariant(size()));
+    setHeader(QNetworkRequest::ContentTypeHeader, QVariant("text/html; charset=UTF-8"));
+
+    // The following rigamole is needed to delay emitting readyRead() / finished() after until the
+    // connections to those signals have been set up.
+    //
+    // We use a queued signal here. This will call initSlot after processing has returned to the
+    // event loop.
+    connect(this, SIGNAL(initSignal()), this, SLOT(initSlot()), Qt::QueuedConnection);
+    emit initSignal();
+}
+
+prefix_ void pykit::detail::InternalServerReply::initSlot()
+{
+    emit readyRead();
+    emit finished();
+}
+
+prefix_ bool pykit::detail::InternalServerReply::atEnd()
+    const
+{ return buffer_.atEnd(); }
+
+prefix_ qint64 pykit::detail::InternalServerReply::bytesAvailable()
+    const
+{ return buffer_.bytesAvailable(); }
+
+prefix_ qint64 pykit::detail::InternalServerReply::bytesToWrite()
+    const
+{ return buffer_.bytesToWrite(); }
+
+prefix_ bool pykit::detail::InternalServerReply::canReadLine()
+    const
+{ return buffer_.canReadLine(); }
+
+prefix_ bool pykit::detail::InternalServerReply::isSequential()
+    const
+{ return buffer_.isSequential(); }
+
+prefix_ qint64 pykit::detail::InternalServerReply::pos()
+    const
+{ return buffer_.pos(); }
+
+prefix_ bool pykit::detail::InternalServerReply::reset()
+{ return buffer_.reset(); }
+
+prefix_ bool pykit::detail::InternalServerReply::seek(qint64 pos)
+{ return buffer_.seek(pos); }
+
+prefix_ qint64 pykit::detail::InternalServerReply::size()
+    const
+{ return buffer_.size(); }
+
+prefix_ bool pykit::detail::InternalServerReply::waitForBytesWritten(int msecs)
+{ return buffer_.waitForBytesWritten(msecs); }
+
+prefix_ bool pykit::detail::InternalServerReply::waitForReadyRead(int msecs)
+{ return buffer_.waitForReadyRead(msecs); }
+
+prefix_ qint64 pykit::detail::InternalServerReply::readData(char * data, qint64 maxSize)
+{ return buffer_.read(data,maxSize); }
+
+prefix_ qint64 pykit::detail::InternalServerReply::writeData(char const * data, qint64 maxSize)
+{ return buffer_.write(data,maxSize); }
+
+prefix_ void pykit::detail::InternalServerReply::abort()
+{}
+
+prefix_ void pykit::detail::InternalServerReply::clearResponse()
+{
+    buffer_.buffer().clear();
+}
+
+///////////////////////////////////////////////////////////////////////////
+// pykit::Request
+
+prefix_ void pykit::Request::write(std::string const & data)
+{
+    reply_.write(data.c_str());
+}
+
+prefix_ void pykit::Request::reset()
+{
+    reply_.clearResponse();
+}
+
+prefix_ void pykit::Request::setContentType(std::string const & contentType)
+{
+    reply_.setHeader(QNetworkRequest::ContentTypeHeader, QVariant(contentType.c_str()));
+}
+
+prefix_ void pykit::Request::setLocation(std::string const & location)
+{
+    reply_.setHeader(QNetworkRequest::LocationHeader, QVariant(location.c_str()));
+}
+
+prefix_ QUrl pykit::Request::url()
+    const
+{
+    return reply_.url();
+}
+
+prefix_ pykit::Request::Request(detail::InternalServerReply & reply)
+    : reply_ (reply)
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// pykit::InternalNetworkAccessManager
+
+prefix_ pykit::InternalNetworkAccessManager::
+InternalNetworkAccessManager(QNetworkAccessManager * manager, QObject * parent,
+                             Publisher * publisher)
+    : QNetworkAccessManager(parent), publisher_ (publisher)
+{
+    setCache(manager->cache());
+    setCookieJar(manager->cookieJar());
+    setProxy(manager->proxy());
+    setProxyFactory(manager->proxyFactory());
+}
+
+prefix_ QNetworkReply *
+pykit::InternalNetworkAccessManager::createRequest(Operation operation,
+                                                        QNetworkRequest const & request,
+                                                        QIODevice * device)
+{
+    if (request.url().scheme() != "srv")
+        return QNetworkAccessManager::createRequest(operation, request, device);
+
+    return new detail::InternalServerReply(operation, request, publisher_);
+}
+
+#include "Publisher.moc"
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "Publisher.mpp"
+
+\f
+// 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.hh b/Publisher.hh
new file mode 100644 (file)
index 0000000..5e95625
--- /dev/null
@@ -0,0 +1,83 @@
+// $Id$
+//
+// Copyright (C) 2010
+//     Stefan Bund <info@j32.de>
+
+/** \file
+    \brief InternalNetworkAccessManager public header */
+
+#ifndef HH_PyKit_Publisher_
+#define HH_PyKit_Publisher_ 1
+
+// Custom includes
+#include <QNetworkAccessManager>
+#include <QNetworkRequest>
+#include <QNetworkReply>
+#include <QBuffer>
+
+//#include "Publisher.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace pykit {
+
+    namespace detail { class InternalServerReply; }
+
+    class Request
+    {
+    public:
+        void write(std::string const & data);
+        void reset();
+
+        void setContentType(std::string const & contentType);
+        void setLocation(std::string const & location);
+
+        QUrl url() const;
+
+    private:
+        Request(detail::InternalServerReply & reply);
+
+        detail::InternalServerReply & reply_;
+
+        friend class detail::InternalServerReply;
+    };
+
+    class Publisher
+    {
+    public:
+        virtual ~Publisher() {}
+        virtual void publish(Request & request) = 0;
+    };
+
+    class InternalNetworkAccessManager
+        : public QNetworkAccessManager
+    {
+        Q_OBJECT;
+    public:
+        InternalNetworkAccessManager(QNetworkAccessManager * manager, QObject * parent,
+                                     Publisher * publisher);
+
+        QNetworkReply * createRequest(Operation operation, QNetworkRequest const & request,
+                                      QIODevice * device);
+
+    private:
+        Publisher * publisher_;
+    };
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "Publisher.cci"
+//#include "Publisher.ct"
+//#include "Publisher.cti"
+#endif
+
+\f
+// 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/PythonPublisher.cc b/PythonPublisher.cc
new file mode 100644 (file)
index 0000000..c75fc88
--- /dev/null
@@ -0,0 +1,458 @@
+// $Id$
+//
+// Copyright (C) 2010
+//     Stefan Bund <info@j32.de>
+
+/** \file
+    \brief PythonPublisher non-inline non-template implementation */
+
+#include "PythonPublisher.hh"
+//#include "PythonPublisher.ih"
+
+// Custom includes
+#include "Publisher.hh"
+
+//#include "PythonPublisher.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+namespace py = boost::python;
+
+namespace {
+
+    struct PublisherPyWrapper
+        : public pykit::Publisher, py::wrapper<pykit::Publisher>
+    {
+        virtual void publish(pykit::Request & request)
+            { get_override("publish")(request); }
+    };
+
+    namespace pyconvert {
+
+        struct QString_PyUnicode
+        {
+            static PyObject * convert(QString const & s)
+                {
+                    std::wstring ws (s.toStdWString());
+                    return PyUnicode_FromWideChar(ws.c_str(), ws.length());
+                }
+        };
+
+        struct PyUnicode_QString
+        {
+            static void * convertible(PyObject * o)
+                {
+                    return PyUnicode_Check(o) ? o : 0;
+                }
+
+            static void construct(PyObject * o,
+                                  py::converter::rvalue_from_python_stage1_data * data)
+                {
+                    unsigned length (PyUnicode_GetSize(o));
+                    std::wstring ws (length, 0);
+                    // Hmm ... I don't want to copy the stupid data TWICE but this
+                    // breaks the standard ... who cares ?
+                    PyUnicode_AsWideChar(reinterpret_cast<PyUnicodeObject *>(o),
+                                         const_cast<wchar_t*>(ws.data()),
+                                         length);
+                    void * storage (((py::converter::rvalue_from_python_storage<QString>*)
+                                     data)->storage.bytes);
+                    *(new (storage) QString()) = QString::fromStdWString(ws);
+                    data->convertible = storage;
+                }
+
+            PyUnicode_QString()
+                {
+                    py::converter::registry::push_back(
+                        &convertible,
+                        &construct,
+                        py::type_id<QString>());
+                }
+        };
+
+        struct QByteArray_PyString
+        {
+            static PyObject * convert(QByteArray const & s)
+                {
+                    return boost::python::incref(boost::python::object(s.constData()).ptr());
+                }
+        };
+
+        struct PyString_QByteArray
+        {
+            static void * convertible(PyObject * o)
+                {
+                    return PyString_Check(o) ? o : 0;
+                }
+
+            static void construct(PyObject * o,
+                                  py::converter::rvalue_from_python_stage1_data * data)
+                {
+                    const char * value (PyString_AsString(o));
+                    void * storage (((py::converter::rvalue_from_python_storage<QByteArray>*)
+                                     data)->storage.bytes);
+                    new (storage) QByteArray(value);
+                    data->convertible = storage;
+                }
+
+            PyString_QByteArray()
+                {
+                    py::converter::registry::push_back(
+                        &convertible,
+                        &construct,
+                        py::type_id<QByteArray>());
+                }
+        };
+
+    }
+
+    QString QUrl_toString_noargs(QUrl const & url)
+    { return url.toString(); }
+
+}
+
+#define MEMFNP(ret, cls, nam, arg) static_cast<ret (cls::*)arg>(&cls::nam)
+
+BOOST_PYTHON_MODULE(_qt)
+{
+    py::to_python_converter<QString, pyconvert::QString_PyUnicode>();
+    pyconvert::PyUnicode_QString register_PyUnicode_QString;
+
+    py::to_python_converter<QByteArray, pyconvert::QByteArray_PyString>();
+    pyconvert::PyString_QByteArray register_PyString_QByteArray;
+
+    // Missing converters:
+    //    QPair <-> tuple
+    //    QList <-> vector
+
+        // QUrl ()
+    py::class_<QUrl>("QUrl", py::init<>())
+        // QUrl ( const QString & url )
+        .def(py::init<QString const &>())
+        // QUrl ( const QUrl & other )
+        .def(py::init<QUrl const &>())
+        // QUrl ( const QString & url, ParsingMode parsingMode )
+        // .def(init<QString const &, ParsingMode>())
+        // ~QUrl ()
+        // void   addEncodedQueryItem ( const QByteArray & key, const QByteArray & value )
+        .def("addEncodedQueryItem",
+             MEMFNP(void, QUrl, addEncodedQueryItem,
+                    ( const QByteArray & key, const QByteArray & value )))
+        // void   addQueryItem ( const QString & key, const QString & value )
+        .def("addQueryItem",
+             MEMFNP(void, QUrl, addQueryItem,
+                    ( const QString & key, const QString & value )))
+        // QList<QByteArray>   allEncodedQueryItemValues ( const QByteArray & key ) const
+        // .def("allEncodedQueryItemValues",
+        //      MEMFNP(QList<QByteArray>, QUrl, allEncodedQueryItemValues,
+        //             ( const QByteArray & key ) const))
+        // QStringList   allQueryItemValues ( const QString & key ) const
+        // .def("allQueryItemValues",
+        //      MEMFNP(QStringList, QUrl, allQueryItemValues,
+        //             ( const QString & key ) const))
+        // QString   authority () const
+        .def("authority",
+             MEMFNP(QString, QUrl, authority,
+                    () const))
+        // void   clear ()
+        .def("clear",
+             MEMFNP(void, QUrl, clear,
+                    ()))
+        // QByteArray   encodedFragment () const
+        .def("encodedFragment",
+             MEMFNP(QByteArray, QUrl, encodedFragment,
+                    () const))
+        // QByteArray   encodedHost () const
+        .def("encodedHost",
+             MEMFNP(QByteArray, QUrl, encodedHost,
+                    () const))
+        // QByteArray   encodedPassword () const
+        .def("encodedPassword",
+             MEMFNP(QByteArray, QUrl, encodedPassword,
+                    () const))
+        // QByteArray   encodedPath () const
+        .def("encodedPath",
+             MEMFNP(QByteArray, QUrl, encodedPath,
+                    () const))
+        // QByteArray   encodedQuery () const
+        .def("encodedQuery",
+             MEMFNP(QByteArray, QUrl, encodedQuery,
+                    () const))
+        // QByteArray   encodedQueryItemValue ( const QByteArray & key ) const
+        .def("encodedQueryItemValue",
+             MEMFNP(QByteArray, QUrl, encodedQueryItemValue,
+                    ( const QByteArray & key ) const))
+        // QList<QPair<QByteArray, QByteArray> >   encodedQueryItems () const
+        // .def("encodedQueryItems",
+        //      MEMFNP(QList<QPair<QByteArray, QByteArray> >, QUrl, encodedQueryItems,
+        //             () const))
+        // QByteArray   encodedUserName () const
+        .def("encodedUserName",
+             MEMFNP(QByteArray, QUrl, encodedUserName,
+                    () const))
+        // QString   errorString () const
+        .def("errorString",
+             MEMFNP(QString, QUrl, errorString,
+                    () const))
+        // QString   fragment () const
+        .def("fragment",
+             MEMFNP(QString, QUrl, fragment,
+                    () const))
+        // bool   hasEncodedQueryItem ( const QByteArray & key ) const
+        .def("hasEncodedQueryItem",
+             MEMFNP(bool, QUrl, hasEncodedQueryItem,
+                    ( const QByteArray & key ) const))
+        // bool   hasFragment () const
+        .def("hasFragment",
+             MEMFNP(bool, QUrl, hasFragment,
+                    () const))
+        // bool   hasQuery () const
+        .def("hasQuery",
+             MEMFNP(bool, QUrl, hasQuery,
+                    () const))
+        // bool   hasQueryItem ( const QString & key ) const
+        .def("hasQueryItem",
+             MEMFNP(bool, QUrl, hasQueryItem,
+                    ( const QString & key ) const))
+        // QString   host () const
+        .def("host",
+             MEMFNP(QString, QUrl, host,
+                    () const))
+        // bool   isEmpty () const
+        .def("isEmpty",
+             MEMFNP(bool, QUrl, isEmpty,
+                    () const))
+        // bool   isParentOf ( const QUrl & childUrl ) const
+        .def("isParentOf",
+             MEMFNP(bool, QUrl, isParentOf,
+                    ( const QUrl & childUrl ) const))
+        // bool   isRelative () const
+        .def("isRelative",
+             MEMFNP(bool, QUrl, isRelative,
+                    () const))
+        // bool   isValid () const
+        .def("isValid",
+             MEMFNP(bool, QUrl, isValid,
+                    () const))
+        // QString   password () const
+        .def("password",
+             MEMFNP(QString, QUrl, password,
+                    () const))
+        // QString   path () const
+        .def("path",
+             MEMFNP(QString, QUrl, path,
+                    () const))
+        // int   port () const
+        .def("port",
+             MEMFNP(int, QUrl, port,
+                    () const))
+        // int   port ( int defaultPort ) const
+        .def("port",
+             MEMFNP(int, QUrl, port,
+                    ( int defaultPort ) const))
+        // QString   queryItemValue ( const QString & key ) const
+        .def("queryItemValue",
+             MEMFNP(QString, QUrl, queryItemValue,
+                    ( const QString & key ) const))
+        // QList<QPair<QString, QString> >   queryItems () const
+        // .def("queryItems",
+        //      MEMFNP(QList<QPair<QString, QString> >, QUrl, queryItems,
+        //             () const))
+        // char   queryPairDelimiter () const
+        .def("queryPairDelimiter",
+             MEMFNP(char, QUrl, queryPairDelimiter,
+                    () const))
+        // char   queryValueDelimiter () const
+        .def("queryValueDelimiter",
+             MEMFNP(char, QUrl, queryValueDelimiter,
+                    () const))
+        // void   removeAllEncodedQueryItems ( const QByteArray & key )
+        .def("removeAllEncodedQueryItems",
+             MEMFNP(void, QUrl, removeAllEncodedQueryItems,
+                    ( const QByteArray & key )))
+        // void   removeAllQueryItems ( const QString & key )
+        .def("removeAllQueryItems",
+             MEMFNP(void, QUrl, removeAllQueryItems,
+                    ( const QString & key )))
+        // void   removeEncodedQueryItem ( const QByteArray & key )
+        .def("removeEncodedQueryItem",
+             MEMFNP(void, QUrl, removeEncodedQueryItem,
+                    ( const QByteArray & key )))
+        // void   removeQueryItem ( const QString & key )
+        .def("removeQueryItem",
+             MEMFNP(void, QUrl, removeQueryItem,
+                    ( const QString & key )))
+        // QUrl   resolved ( const QUrl & relative ) const
+        .def("resolved",
+             MEMFNP(QUrl, QUrl, resolved,
+                    ( const QUrl & relative ) const))
+        // QString   scheme () const
+        .def("scheme",
+             MEMFNP(QString, QUrl, scheme,
+                    () const))
+        // void   setAuthority ( const QString & authority )
+        .def("setAuthority",
+             MEMFNP(void, QUrl, setAuthority,
+                    ( const QString & authority )))
+        // void   setEncodedFragment ( const QByteArray & fragment )
+        .def("setEncodedFragment",
+             MEMFNP(void, QUrl, setEncodedFragment,
+                    ( const QByteArray & fragment )))
+        // void   setEncodedHost ( const QByteArray & host )
+        .def("setEncodedHost",
+             MEMFNP(void, QUrl, setEncodedHost,
+                    ( const QByteArray & host )))
+        // void   setEncodedPassword ( const QByteArray & password )
+        .def("setEncodedPassword",
+             MEMFNP(void, QUrl, setEncodedPassword,
+                    ( const QByteArray & password )))
+        // void   setEncodedPath ( const QByteArray & path )
+        .def("setEncodedPath",
+             MEMFNP(void, QUrl, setEncodedPath,
+                    ( const QByteArray & path )))
+        // void   setEncodedQuery ( const QByteArray & query )
+        .def("setEncodedQuery",
+             MEMFNP(void, QUrl, setEncodedQuery,
+                    ( const QByteArray & query )))
+        // void   setEncodedQueryItems ( const QList<QPair<QByteArray, QByteArray> > & query )
+        // .def("setEncodedQueryItems",
+        //      MEMFNP(void, QUrl, setEncodedQueryItems,
+        //             ( const QList<QPair<QByteArray, QByteArray> > & query )))
+        // void   setEncodedUrl ( const QByteArray & encodedUrl )
+        .def("setEncodedUrl",
+             MEMFNP(void, QUrl, setEncodedUrl,
+                    ( const QByteArray & encodedUrl )))
+        // void   setEncodedUrl ( const QByteArray & encodedUrl, ParsingMode parsingMode )
+        // .def("setEncodedUrl",
+        //      MEMFNP(void, QUrl, setEncodedUrl,
+        //             ( const QByteArray & encodedUrl, ParsingMode parsingMode )))
+        // void   setEncodedUserName ( const QByteArray & userName )
+        .def("setEncodedUserName",
+             MEMFNP(void, QUrl, setEncodedUserName,
+                    ( const QByteArray & userName )))
+        // void   setFragment ( const QString & fragment )
+        .def("setFragment",
+             MEMFNP(void, QUrl, setFragment,
+                    ( const QString & fragment )))
+        // void   setHost ( const QString & host )
+        .def("setHost",
+             MEMFNP(void, QUrl, setHost,
+                    ( const QString & host )))
+        // void   setPassword ( const QString & password )
+        .def("setPassword",
+             MEMFNP(void, QUrl, setPassword,
+                    ( const QString & password )))
+        // void   setPath ( const QString & path )
+        .def("setPath",
+             MEMFNP(void, QUrl, setPath,
+                    ( const QString & path )))
+        // void   setPort ( int port )
+        .def("setPort",
+             MEMFNP(void, QUrl, setPort,
+                    ( int port )))
+        // void   setQueryDelimiters ( char valueDelimiter, char pairDelimiter )
+        .def("setQueryDelimiters",
+             MEMFNP(void, QUrl, setQueryDelimiters,
+                    ( char valueDelimiter, char pairDelimiter )))
+        // void   setQueryItems ( const QList<QPair<QString, QString> > & query )
+        // .def("setQueryItems",
+        //      MEMFNP(void, QUrl, setQueryItems,
+        //             ( const QList<QPair<QString, QString> > & query )))
+        // void   setScheme ( const QString & scheme )
+        .def("setScheme",
+             MEMFNP(void, QUrl, setScheme,
+                    ( const QString & scheme )))
+        // void   setUrl ( const QString & url )
+        .def("setUrl",
+             MEMFNP(void, QUrl, setUrl,
+                    ( const QString & url )))
+        // void   setUrl ( const QString & url, ParsingMode parsingMode )
+        // .def("setUrl",
+        //      MEMFNP(void, QUrl, setUrl,
+        //             ( const QString & url, ParsingMode parsingMode )))
+        // void   setUserInfo ( const QString & userInfo )
+        .def("setUserInfo",
+             MEMFNP(void, QUrl, setUserInfo,
+                    ( const QString & userInfo )))
+        // void   setUserName ( const QString & userName )
+        .def("setUserName",
+             MEMFNP(void, QUrl, setUserName,
+                    ( const QString & userName )))
+        // QByteArray   toEncoded ( FormattingOptions options = None ) const
+        // .def("toEncoded",
+        //      MEMFNP(QByteArray, QUrl, toEncoded,
+        //             ( FormattingOptions options = None ) const))
+        // QString   toLocalFile () const
+        .def("toLocalFile",
+             MEMFNP(QString, QUrl, toLocalFile,
+                    () const))
+        // QString   toString ( FormattingOptions options = None ) const
+        .def("__unicode__", &QUrl_toString_noargs)
+        // QString   userInfo () const
+        .def("userInfo",
+             MEMFNP(QString, QUrl, userInfo,
+                    () const))
+        // QString   userName () const
+        .def("userName",
+             MEMFNP(QString, QUrl, userName,
+                    () const))
+
+        // bool   operator!= ( const QUrl & url ) const
+        // QUrl &   operator= ( const QUrl & url )
+        // QUrl &   operator= ( const QString & url )
+        // bool   operator== ( const QUrl & url ) const
+        ;
+}
+
+BOOST_PYTHON_MODULE(_pykit)
+{
+    py::class_<pykit::Request>("Request", py::no_init)
+        .def("write", &pykit::Request::write)
+        .def("reset", &pykit::Request::reset)
+        .def("setContentType", &pykit::Request::setContentType)
+        .def("setLocation", &pykit::Request::setLocation)
+        .def("url", &pykit::Request::url)
+        ;
+
+    py::class_<PublisherPyWrapper, boost::noncopyable>("Publisher")
+        .def("publish", py::pure_virtual(&pykit::Publisher::publish))
+        ;
+}
+
+prefix_ pykit::PythonPublisher::PythonPublisher(std::string initPy)
+{
+    PYTHON_PREPARE_IMPORT(_pykit);
+    PYTHON_PREPARE_IMPORT(_qt);
+    Py_Initialize();
+    py::object mainModule_ = py::import("__main__");
+    mainNamespace_ = py::extract<py::dict>(mainModule_.attr("__dict__"));
+    mainNamespace_["__file__"] = py::str(initPy.c_str());
+    py::object ignored (
+        py::exec_file(initPy.c_str(), mainNamespace_, mainNamespace_));
+    pythonPublisher_ = py::extract<Publisher*>(mainNamespace_["publisher"]);
+}
+
+prefix_ void pykit::PythonPublisher::publish(Request & request)
+{
+    try {
+        pythonPublisher_->publish(request);
+    }
+    catch (py::error_already_set & ex) {
+        PyErr_Print();
+    }
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "PythonPublisher.mpp"
+
+\f
+// 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/PythonPublisher.hh b/PythonPublisher.hh
new file mode 100644 (file)
index 0000000..b00c983
--- /dev/null
@@ -0,0 +1,54 @@
+// $Id$
+//
+// Copyright (C) 2010
+//     Stefan Bund <info@j32.de>
+
+/** \file
+    \brief PythonPublisher public header */
+
+#ifndef HH_PyKit_PythonPublisher_
+#define HH_PyKit_PythonPublisher_ 1
+
+// Custom includes
+#include <boost/python.hpp>
+#include "Publisher.hh"
+
+//#include "PythonPublisher.mpp"
+///////////////////////////////hh.p////////////////////////////////////////
+
+namespace pykit {
+
+    class PythonPublisher
+        : public Publisher
+    {
+    public:
+        PythonPublisher(std::string initPy);
+
+        void publish(Request & request);
+
+    private:
+        boost::python::dict mainNamespace_;
+        Publisher * pythonPublisher_;
+    };
+
+#   define PYTHON_PREPARE_IMPORT(module) \
+        PyImport_AppendInittab(const_cast<char*>(#module), init ## module)
+
+}
+
+///////////////////////////////hh.e////////////////////////////////////////
+//#include "PythonPublisher.cci"
+//#include "PythonPublisher.ct"
+//#include "PythonPublisher.cti"
+#endif
+
+\f
+// 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/SConscript b/SConscript
new file mode 100644 (file)
index 0000000..5503bac
--- /dev/null
@@ -0,0 +1,17 @@
+# -*- python -*-
+
+Import('env')
+
+# QtSvg and QtXml are needed by some plugins ...
+env.EnableQt4Modules([ 'QtWebKit', 'QtNetwork', 'QtSvg', 'QtXml', 'QtGui', 'QtCore' ])
+
+env.Append(
+    CXXFLAGS          = [ '-Wall', '-Wextra' ],
+    CPPPATH           = [ '$LIBPYTHONINCLUDES' ],
+    LIBS              = [ '$LIBBOOSTPYTHON', '$LIBPYTHON' ]
+)
+
+sources = env.Qt4Glob()
+
+pykit = env.Program('pykit', sources)
+env.Default(pykit)
diff --git a/SConstruct b/SConstruct
new file mode 100644 (file)
index 0000000..4fae7cb
--- /dev/null
@@ -0,0 +1,22 @@
+# -*- python -*-
+
+import os
+
+env = Environment(ENV = os.environ)
+env.Tool('qt4',['../site_scons/qtscons'])
+
+env.SetDefault(
+    PYTHON            = 'python',
+    LIBPYTHON         = 'python$PYTHONVERSION',
+    LIBPYTHONINCLUDES = '/usr/include/python$PYTHONVERSION',
+    LIBBOOSTPYTHON    = 'boost_python'
+)
+
+env.SetDefault(
+    PYTHONVERSION     = os.popen(env.subst(
+            """$PYTHON -c 'import sys; print".".join(map(str,sys.version_info[:2]))'""")).read(),
+)
+
+Export('env')
+
+env.SConscript("SConscript")
diff --git a/init.py b/init.py
new file mode 100644 (file)
index 0000000..b0981f9
--- /dev/null
+++ b/init.py
@@ -0,0 +1,8 @@
+import _pykit, _qt
+
+class Publisher(_pykit.Publisher):
+    def publish(self, request):
+        request.setContentType('text/html')
+        request.write("<html><body><h1>PyKit up and running</h1></body></html>")
+
+publisher = Publisher()
diff --git a/main.cc b/main.cc
new file mode 100644 (file)
index 0000000..84a675f
--- /dev/null
+++ b/main.cc
@@ -0,0 +1,94 @@
+// $Id$
+//
+// Copyright (C) 2010
+//     Stefan Bund <info@j32.de>
+
+/** \file
+    \brief main non-inline non-template implementation */
+
+//#include "main.hh"
+//#include "main.ih"
+
+// Custom includes
+#include <stdlib.h>
+#include <iostream>
+#include <QApplication>
+#include <QSplashScreen>
+#include <QSettings>
+#include <boost/python.hpp>
+#include <boost/scoped_ptr.hpp>
+#include "MainWindow.hh"
+#include "PythonPublisher.hh"
+
+//#include "main.mpp"
+#define prefix_
+///////////////////////////////cc.p////////////////////////////////////////
+
+int main(int argc, char *argv[])
+{
+    try {
+        QApplication app (argc, argv);
+
+        QSettings settings ("pykit.ini", QSettings::IniFormat);
+        QStringList arguments (app.arguments());
+        settings.beginGroup("AppData");
+
+        app.setApplicationName(settings.value("name").toString());
+        app.setApplicationVersion(settings.value("version").toString());
+        app.setOrganizationDomain(settings.value("organization").toString());
+        app.setOrganizationName(settings.value("organization").toString());
+
+        QString splashPath (settings.value("splash").toString());
+        boost::scoped_ptr<QSplashScreen> splash;
+        if (!splashPath.isEmpty()) {
+            QPixmap splashPixmap (settings.value("splash").toString());
+            splash.reset(new QSplashScreen (splashPixmap));
+            splash->show();
+        }
+
+        QString iconPath (settings.value("icon").toString());
+
+        settings.endGroup();
+        settings.beginGroup("Viewer");
+
+        pykit::PythonPublisher publisher (settings.value("init").toString().toStdString());
+
+        QString url (settings.value("home").toString());
+        if (arguments.size()>1)
+            url = arguments.at(1);
+        pykit::MainWindow window (QUrl(url), &publisher);
+        window.setWindowTitle(app.applicationName());
+        if (!iconPath.isEmpty())
+            window.setWindowIcon(QIcon(iconPath));
+        window.setWindowIconText(window.windowTitle());
+
+        window.show();
+        if (splash)
+            splash->finish(&window);
+
+        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;
+    }
+}
+
+///////////////////////////////cc.e////////////////////////////////////////
+#undef prefix_
+//#include "main.mpp"
+
+\f
+// 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/pykit.ini b/pykit.ini
new file mode 100644 (file)
index 0000000..d490f6f
--- /dev/null
+++ b/pykit.ini
@@ -0,0 +1,8 @@
+[AppData]
+name=PyKit
+version=0.1
+organization=g0dil.de
+
+[Viewer]
+init=init.py
+home=srv:///