typo fix
[pykit.git] / PythonPublisher.cc
index c75fc88..f1699d4 100644 (file)
 //#include "PythonPublisher.ih"
 
 // Custom includes
+#include <iostream>
+#include <boost/python.hpp>
 #include "Publisher.hh"
+#include <QDesktopServices>
+#include <QWebHistory>
+#include "Viewer.hh"
 
 //#include "PythonPublisher.mpp"
 #define prefix_
 
 namespace py = boost::python;
 
+struct pykit::PythonPublisher::Impl
+{
+    boost::python::dict mainNamespace;
+    Publisher * pythonPublisher;
+};
+
+#define PYTHON_EXTERN_MODULE(module) \
+    extern "C" { void init ## module (); }
+#define PYTHON_PREPARE_IMPORT(module) \
+    PyImport_AppendInittab(const_cast<char*>(#module), init ## module)
+
 namespace {
 
     struct PublisherPyWrapper
@@ -34,7 +50,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 +104,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<QByteArray>*)
                                      data)->storage.bytes);
-                    new (storage) QByteArray(value);
+                    new (storage) QByteArray(value,length);
                     data->convertible = storage;
                 }
 
@@ -404,6 +421,30 @@ BOOST_PYTHON_MODULE(_qt)
         ;
 }
 
+namespace {
+
+    bool canGoBack()
+    {
+        return pykit::Viewer::instance()->page()->history()->canGoBack();
+    }
+
+    bool canGoForward()
+    {
+        return pykit::Viewer::instance()->page()->history()->canGoForward();
+    }
+
+    class ErrorCatcher
+    {
+    public:
+        explicit ErrorCatcher(std::string & out) : out_ (out) {}
+        void write(std::string const & msg)
+            { std::cerr << "append: " << msg; out_ += msg; }
+    private:
+        std::string & out_;
+    };
+
+}
+
 BOOST_PYTHON_MODULE(_pykit)
 {
     py::class_<pykit::Request>("Request", py::no_init)
@@ -411,34 +452,74 @@ BOOST_PYTHON_MODULE(_pykit)
         .def("reset", &pykit::Request::reset)
         .def("setContentType", &pykit::Request::setContentType)
         .def("setLocation", &pykit::Request::setLocation)
+        .def("setRawHeader", &pykit::Request::setHeader)
+        .def("setStatusCode", &pykit::Request::setStatusCode)
         .def("url", &pykit::Request::url)
+        .def("postData", &pykit::Request::postData)
+        .def("operation", &pykit::Request::operation)
+        .def("postContentType", &pykit::Request::postContentType)
         ;
 
     py::class_<PublisherPyWrapper, boost::noncopyable>("Publisher")
         .def("publish", py::pure_virtual(&pykit::Publisher::publish))
         ;
+
+    py::class_<ErrorCatcher>("ErrorCatcher", py::no_init)
+        .def("write", &ErrorCatcher::write)
+        ;
+
+    py::def("openUrl", &QDesktopServices::openUrl);
+
+    py::def("canGoBack", &canGoBack);
+    py::def("canGoForward", &canGoForward);
+}
+
+PYTHON_EXTERN_MODULE(_httpapi);
+
+prefix_ pykit::PythonPublisher::PythonPublisher()
+    : impl_ (new Impl)
+{
+    std::string pyError;
+    try {
+        PYTHON_PREPARE_IMPORT(_pykit);
+        PYTHON_PREPARE_IMPORT(_qt);
+        PYTHON_PREPARE_IMPORT(_httpapi);
+        Py_Initialize();
+
+        py::import("_pykit");
+        py::object sysModule (py::import("sys"));
+        py::object origStderr (sysModule.attr("stderr"));
+        ErrorCatcher catcher (pyError);
+        sysModule.attr("stderr") = catcher;
+
+        py::object initModule (py::import("init"));
+        impl_->mainNamespace = py::extract<py::dict>(initModule.attr("__dict__"));
+        impl_->pythonPublisher = py::extract<Publisher*>(impl_->mainNamespace["initialize"]());
+
+        sysModule.attr("stderr") = origStderr;
+    }
+    catch (boost::python::error_already_set & ex) {
+        PyErr_Print();
+        throw PythonError(pyError);
+    }
 }
 
-prefix_ pykit::PythonPublisher::PythonPublisher(std::string initPy)
+prefix_ pykit::PythonPublisher::~PythonPublisher()
 {
-    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"]);
+    try {
+        impl_->mainNamespace["shutdown"]();
+    }
+    catch (...) {;}
 }
 
 prefix_ void pykit::PythonPublisher::publish(Request & request)
 {
     try {
-        pythonPublisher_->publish(request);
+        impl_->pythonPublisher->publish(request);
     }
     catch (py::error_already_set & ex) {
         PyErr_Print();
+        PyErr_Clear();
     }
 }