typo fix
[pykit.git] / PythonPublisher.cc
1 // $Id$
2 //
3 // Copyright (C) 2010
4 //     Stefan Bund <info@j32.de>
5
6 /** \file
7     \brief PythonPublisher non-inline non-template implementation */
8
9 #include "PythonPublisher.hh"
10 //#include "PythonPublisher.ih"
11
12 // Custom includes
13 #include <iostream>
14 #include <boost/python.hpp>
15 #include "Publisher.hh"
16 #include <QDesktopServices>
17 #include <QWebHistory>
18 #include "Viewer.hh"
19
20 //#include "PythonPublisher.mpp"
21 #define prefix_
22 ///////////////////////////////cc.p////////////////////////////////////////
23
24 namespace py = boost::python;
25
26 struct pykit::PythonPublisher::Impl
27 {
28     boost::python::dict mainNamespace;
29     Publisher * pythonPublisher;
30 };
31
32 #define PYTHON_EXTERN_MODULE(module) \
33     extern "C" { void init ## module (); }
34 #define PYTHON_PREPARE_IMPORT(module) \
35     PyImport_AppendInittab(const_cast<char*>(#module), init ## module)
36
37 namespace {
38
39     struct PublisherPyWrapper
40         : public pykit::Publisher, py::wrapper<pykit::Publisher>
41     {
42         virtual void publish(pykit::Request & request)
43             { get_override("publish")(request); }
44     };
45
46     namespace pyconvert {
47
48         struct QString_PyUnicode
49         {
50             static PyObject * convert(QString const & s)
51                 {
52                     std::wstring ws (s.toStdWString());
53                     return PyUnicode_FromWideChar(ws.data(), ws.length());
54                 }
55         };
56
57         struct PyUnicode_QString
58         {
59             static void * convertible(PyObject * o)
60                 {
61                     return PyUnicode_Check(o) ? o : 0;
62                 }
63
64             static void construct(PyObject * o,
65                                   py::converter::rvalue_from_python_stage1_data * data)
66                 {
67                     unsigned length (PyUnicode_GetSize(o));
68                     std::wstring ws (length, 0);
69                     // Hmm ... I don't want to copy the stupid data TWICE but this
70                     // breaks the standard ... who cares ?
71                     PyUnicode_AsWideChar(reinterpret_cast<PyUnicodeObject *>(o),
72                                          const_cast<wchar_t*>(ws.data()),
73                                          length);
74                     void * storage (((py::converter::rvalue_from_python_storage<QString>*)
75                                      data)->storage.bytes);
76                     *(new (storage) QString()) = QString::fromStdWString(ws);
77                     data->convertible = storage;
78                 }
79
80             PyUnicode_QString()
81                 {
82                     py::converter::registry::push_back(
83                         &convertible,
84                         &construct,
85                         py::type_id<QString>());
86                 }
87         };
88
89         struct QByteArray_PyString
90         {
91             static PyObject * convert(QByteArray const & s)
92                 {
93                     return boost::python::incref(boost::python::object(s.constData()).ptr());
94                 }
95         };
96
97         struct PyString_QByteArray
98         {
99             static void * convertible(PyObject * o)
100                 {
101                     return PyString_Check(o) ? o : 0;
102                 }
103
104             static void construct(PyObject * o,
105                                   py::converter::rvalue_from_python_stage1_data * data)
106                 {
107                     unsigned length (PyString_Size(o));
108                     const char * value (PyString_AsString(o));
109                     void * storage (((py::converter::rvalue_from_python_storage<QByteArray>*)
110                                      data)->storage.bytes);
111                     new (storage) QByteArray(value,length);
112                     data->convertible = storage;
113                 }
114
115             PyString_QByteArray()
116                 {
117                     py::converter::registry::push_back(
118                         &convertible,
119                         &construct,
120                         py::type_id<QByteArray>());
121                 }
122         };
123
124     }
125
126     QString QUrl_toString_noargs(QUrl const & url)
127     { return url.toString(); }
128
129 }
130
131 #define MEMFNP(ret, cls, nam, arg) static_cast<ret (cls::*)arg>(&cls::nam)
132
133 BOOST_PYTHON_MODULE(_qt)
134 {
135     py::to_python_converter<QString, pyconvert::QString_PyUnicode>();
136     pyconvert::PyUnicode_QString register_PyUnicode_QString;
137
138     py::to_python_converter<QByteArray, pyconvert::QByteArray_PyString>();
139     pyconvert::PyString_QByteArray register_PyString_QByteArray;
140
141     // Missing converters:
142     //    QPair <-> tuple
143     //    QList <-> vector
144
145         // QUrl ()
146     py::class_<QUrl>("QUrl", py::init<>())
147         // QUrl ( const QString & url )
148         .def(py::init<QString const &>())
149         // QUrl ( const QUrl & other )
150         .def(py::init<QUrl const &>())
151         // QUrl ( const QString & url, ParsingMode parsingMode )
152         // .def(init<QString const &, ParsingMode>())
153         // ~QUrl ()
154         // void   addEncodedQueryItem ( const QByteArray & key, const QByteArray & value )
155         .def("addEncodedQueryItem",
156              MEMFNP(void, QUrl, addEncodedQueryItem,
157                     ( const QByteArray & key, const QByteArray & value )))
158         // void   addQueryItem ( const QString & key, const QString & value )
159         .def("addQueryItem",
160              MEMFNP(void, QUrl, addQueryItem,
161                     ( const QString & key, const QString & value )))
162         // QList<QByteArray>   allEncodedQueryItemValues ( const QByteArray & key ) const
163         // .def("allEncodedQueryItemValues",
164         //      MEMFNP(QList<QByteArray>, QUrl, allEncodedQueryItemValues,
165         //             ( const QByteArray & key ) const))
166         // QStringList   allQueryItemValues ( const QString & key ) const
167         // .def("allQueryItemValues",
168         //      MEMFNP(QStringList, QUrl, allQueryItemValues,
169         //             ( const QString & key ) const))
170         // QString   authority () const
171         .def("authority",
172              MEMFNP(QString, QUrl, authority,
173                     () const))
174         // void   clear ()
175         .def("clear",
176              MEMFNP(void, QUrl, clear,
177                     ()))
178         // QByteArray   encodedFragment () const
179         .def("encodedFragment",
180              MEMFNP(QByteArray, QUrl, encodedFragment,
181                     () const))
182         // QByteArray   encodedHost () const
183         .def("encodedHost",
184              MEMFNP(QByteArray, QUrl, encodedHost,
185                     () const))
186         // QByteArray   encodedPassword () const
187         .def("encodedPassword",
188              MEMFNP(QByteArray, QUrl, encodedPassword,
189                     () const))
190         // QByteArray   encodedPath () const
191         .def("encodedPath",
192              MEMFNP(QByteArray, QUrl, encodedPath,
193                     () const))
194         // QByteArray   encodedQuery () const
195         .def("encodedQuery",
196              MEMFNP(QByteArray, QUrl, encodedQuery,
197                     () const))
198         // QByteArray   encodedQueryItemValue ( const QByteArray & key ) const
199         .def("encodedQueryItemValue",
200              MEMFNP(QByteArray, QUrl, encodedQueryItemValue,
201                     ( const QByteArray & key ) const))
202         // QList<QPair<QByteArray, QByteArray> >   encodedQueryItems () const
203         // .def("encodedQueryItems",
204         //      MEMFNP(QList<QPair<QByteArray, QByteArray> >, QUrl, encodedQueryItems,
205         //             () const))
206         // QByteArray   encodedUserName () const
207         .def("encodedUserName",
208              MEMFNP(QByteArray, QUrl, encodedUserName,
209                     () const))
210         // QString   errorString () const
211         .def("errorString",
212              MEMFNP(QString, QUrl, errorString,
213                     () const))
214         // QString   fragment () const
215         .def("fragment",
216              MEMFNP(QString, QUrl, fragment,
217                     () const))
218         // bool   hasEncodedQueryItem ( const QByteArray & key ) const
219         .def("hasEncodedQueryItem",
220              MEMFNP(bool, QUrl, hasEncodedQueryItem,
221                     ( const QByteArray & key ) const))
222         // bool   hasFragment () const
223         .def("hasFragment",
224              MEMFNP(bool, QUrl, hasFragment,
225                     () const))
226         // bool   hasQuery () const
227         .def("hasQuery",
228              MEMFNP(bool, QUrl, hasQuery,
229                     () const))
230         // bool   hasQueryItem ( const QString & key ) const
231         .def("hasQueryItem",
232              MEMFNP(bool, QUrl, hasQueryItem,
233                     ( const QString & key ) const))
234         // QString   host () const
235         .def("host",
236              MEMFNP(QString, QUrl, host,
237                     () const))
238         // bool   isEmpty () const
239         .def("isEmpty",
240              MEMFNP(bool, QUrl, isEmpty,
241                     () const))
242         // bool   isParentOf ( const QUrl & childUrl ) const
243         .def("isParentOf",
244              MEMFNP(bool, QUrl, isParentOf,
245                     ( const QUrl & childUrl ) const))
246         // bool   isRelative () const
247         .def("isRelative",
248              MEMFNP(bool, QUrl, isRelative,
249                     () const))
250         // bool   isValid () const
251         .def("isValid",
252              MEMFNP(bool, QUrl, isValid,
253                     () const))
254         // QString   password () const
255         .def("password",
256              MEMFNP(QString, QUrl, password,
257                     () const))
258         // QString   path () const
259         .def("path",
260              MEMFNP(QString, QUrl, path,
261                     () const))
262         // int   port () const
263         .def("port",
264              MEMFNP(int, QUrl, port,
265                     () const))
266         // int   port ( int defaultPort ) const
267         .def("port",
268              MEMFNP(int, QUrl, port,
269                     ( int defaultPort ) const))
270         // QString   queryItemValue ( const QString & key ) const
271         .def("queryItemValue",
272              MEMFNP(QString, QUrl, queryItemValue,
273                     ( const QString & key ) const))
274         // QList<QPair<QString, QString> >   queryItems () const
275         // .def("queryItems",
276         //      MEMFNP(QList<QPair<QString, QString> >, QUrl, queryItems,
277         //             () const))
278         // char   queryPairDelimiter () const
279         .def("queryPairDelimiter",
280              MEMFNP(char, QUrl, queryPairDelimiter,
281                     () const))
282         // char   queryValueDelimiter () const
283         .def("queryValueDelimiter",
284              MEMFNP(char, QUrl, queryValueDelimiter,
285                     () const))
286         // void   removeAllEncodedQueryItems ( const QByteArray & key )
287         .def("removeAllEncodedQueryItems",
288              MEMFNP(void, QUrl, removeAllEncodedQueryItems,
289                     ( const QByteArray & key )))
290         // void   removeAllQueryItems ( const QString & key )
291         .def("removeAllQueryItems",
292              MEMFNP(void, QUrl, removeAllQueryItems,
293                     ( const QString & key )))
294         // void   removeEncodedQueryItem ( const QByteArray & key )
295         .def("removeEncodedQueryItem",
296              MEMFNP(void, QUrl, removeEncodedQueryItem,
297                     ( const QByteArray & key )))
298         // void   removeQueryItem ( const QString & key )
299         .def("removeQueryItem",
300              MEMFNP(void, QUrl, removeQueryItem,
301                     ( const QString & key )))
302         // QUrl   resolved ( const QUrl & relative ) const
303         .def("resolved",
304              MEMFNP(QUrl, QUrl, resolved,
305                     ( const QUrl & relative ) const))
306         // QString   scheme () const
307         .def("scheme",
308              MEMFNP(QString, QUrl, scheme,
309                     () const))
310         // void   setAuthority ( const QString & authority )
311         .def("setAuthority",
312              MEMFNP(void, QUrl, setAuthority,
313                     ( const QString & authority )))
314         // void   setEncodedFragment ( const QByteArray & fragment )
315         .def("setEncodedFragment",
316              MEMFNP(void, QUrl, setEncodedFragment,
317                     ( const QByteArray & fragment )))
318         // void   setEncodedHost ( const QByteArray & host )
319         .def("setEncodedHost",
320              MEMFNP(void, QUrl, setEncodedHost,
321                     ( const QByteArray & host )))
322         // void   setEncodedPassword ( const QByteArray & password )
323         .def("setEncodedPassword",
324              MEMFNP(void, QUrl, setEncodedPassword,
325                     ( const QByteArray & password )))
326         // void   setEncodedPath ( const QByteArray & path )
327         .def("setEncodedPath",
328              MEMFNP(void, QUrl, setEncodedPath,
329                     ( const QByteArray & path )))
330         // void   setEncodedQuery ( const QByteArray & query )
331         .def("setEncodedQuery",
332              MEMFNP(void, QUrl, setEncodedQuery,
333                     ( const QByteArray & query )))
334         // void   setEncodedQueryItems ( const QList<QPair<QByteArray, QByteArray> > & query )
335         // .def("setEncodedQueryItems",
336         //      MEMFNP(void, QUrl, setEncodedQueryItems,
337         //             ( const QList<QPair<QByteArray, QByteArray> > & query )))
338         // void   setEncodedUrl ( const QByteArray & encodedUrl )
339         .def("setEncodedUrl",
340              MEMFNP(void, QUrl, setEncodedUrl,
341                     ( const QByteArray & encodedUrl )))
342         // void   setEncodedUrl ( const QByteArray & encodedUrl, ParsingMode parsingMode )
343         // .def("setEncodedUrl",
344         //      MEMFNP(void, QUrl, setEncodedUrl,
345         //             ( const QByteArray & encodedUrl, ParsingMode parsingMode )))
346         // void   setEncodedUserName ( const QByteArray & userName )
347         .def("setEncodedUserName",
348              MEMFNP(void, QUrl, setEncodedUserName,
349                     ( const QByteArray & userName )))
350         // void   setFragment ( const QString & fragment )
351         .def("setFragment",
352              MEMFNP(void, QUrl, setFragment,
353                     ( const QString & fragment )))
354         // void   setHost ( const QString & host )
355         .def("setHost",
356              MEMFNP(void, QUrl, setHost,
357                     ( const QString & host )))
358         // void   setPassword ( const QString & password )
359         .def("setPassword",
360              MEMFNP(void, QUrl, setPassword,
361                     ( const QString & password )))
362         // void   setPath ( const QString & path )
363         .def("setPath",
364              MEMFNP(void, QUrl, setPath,
365                     ( const QString & path )))
366         // void   setPort ( int port )
367         .def("setPort",
368              MEMFNP(void, QUrl, setPort,
369                     ( int port )))
370         // void   setQueryDelimiters ( char valueDelimiter, char pairDelimiter )
371         .def("setQueryDelimiters",
372              MEMFNP(void, QUrl, setQueryDelimiters,
373                     ( char valueDelimiter, char pairDelimiter )))
374         // void   setQueryItems ( const QList<QPair<QString, QString> > & query )
375         // .def("setQueryItems",
376         //      MEMFNP(void, QUrl, setQueryItems,
377         //             ( const QList<QPair<QString, QString> > & query )))
378         // void   setScheme ( const QString & scheme )
379         .def("setScheme",
380              MEMFNP(void, QUrl, setScheme,
381                     ( const QString & scheme )))
382         // void   setUrl ( const QString & url )
383         .def("setUrl",
384              MEMFNP(void, QUrl, setUrl,
385                     ( const QString & url )))
386         // void   setUrl ( const QString & url, ParsingMode parsingMode )
387         // .def("setUrl",
388         //      MEMFNP(void, QUrl, setUrl,
389         //             ( const QString & url, ParsingMode parsingMode )))
390         // void   setUserInfo ( const QString & userInfo )
391         .def("setUserInfo",
392              MEMFNP(void, QUrl, setUserInfo,
393                     ( const QString & userInfo )))
394         // void   setUserName ( const QString & userName )
395         .def("setUserName",
396              MEMFNP(void, QUrl, setUserName,
397                     ( const QString & userName )))
398         // QByteArray   toEncoded ( FormattingOptions options = None ) const
399         // .def("toEncoded",
400         //      MEMFNP(QByteArray, QUrl, toEncoded,
401         //             ( FormattingOptions options = None ) const))
402         // QString   toLocalFile () const
403         .def("toLocalFile",
404              MEMFNP(QString, QUrl, toLocalFile,
405                     () const))
406         // QString   toString ( FormattingOptions options = None ) const
407         .def("__unicode__", &QUrl_toString_noargs)
408         // QString   userInfo () const
409         .def("userInfo",
410              MEMFNP(QString, QUrl, userInfo,
411                     () const))
412         // QString   userName () const
413         .def("userName",
414              MEMFNP(QString, QUrl, userName,
415                     () const))
416
417         // bool   operator!= ( const QUrl & url ) const
418         // QUrl &   operator= ( const QUrl & url )
419         // QUrl &   operator= ( const QString & url )
420         // bool   operator== ( const QUrl & url ) const
421         ;
422 }
423
424 namespace {
425
426     bool canGoBack()
427     {
428         return pykit::Viewer::instance()->page()->history()->canGoBack();
429     }
430
431     bool canGoForward()
432     {
433         return pykit::Viewer::instance()->page()->history()->canGoForward();
434     }
435
436     class ErrorCatcher
437     {
438     public:
439         explicit ErrorCatcher(std::string & out) : out_ (out) {}
440         void write(std::string const & msg)
441             { std::cerr << "append: " << msg; out_ += msg; }
442     private:
443         std::string & out_;
444     };
445
446 }
447
448 BOOST_PYTHON_MODULE(_pykit)
449 {
450     py::class_<pykit::Request>("Request", py::no_init)
451         .def("write", &pykit::Request::write)
452         .def("reset", &pykit::Request::reset)
453         .def("setContentType", &pykit::Request::setContentType)
454         .def("setLocation", &pykit::Request::setLocation)
455         .def("setRawHeader", &pykit::Request::setHeader)
456         .def("setStatusCode", &pykit::Request::setStatusCode)
457         .def("url", &pykit::Request::url)
458         .def("postData", &pykit::Request::postData)
459         .def("operation", &pykit::Request::operation)
460         .def("postContentType", &pykit::Request::postContentType)
461         ;
462
463     py::class_<PublisherPyWrapper, boost::noncopyable>("Publisher")
464         .def("publish", py::pure_virtual(&pykit::Publisher::publish))
465         ;
466
467     py::class_<ErrorCatcher>("ErrorCatcher", py::no_init)
468         .def("write", &ErrorCatcher::write)
469         ;
470
471     py::def("openUrl", &QDesktopServices::openUrl);
472
473     py::def("canGoBack", &canGoBack);
474     py::def("canGoForward", &canGoForward);
475 }
476
477 PYTHON_EXTERN_MODULE(_httpapi);
478
479 prefix_ pykit::PythonPublisher::PythonPublisher()
480     : impl_ (new Impl)
481 {
482     std::string pyError;
483     try {
484         PYTHON_PREPARE_IMPORT(_pykit);
485         PYTHON_PREPARE_IMPORT(_qt);
486         PYTHON_PREPARE_IMPORT(_httpapi);
487         Py_Initialize();
488
489         py::import("_pykit");
490         py::object sysModule (py::import("sys"));
491         py::object origStderr (sysModule.attr("stderr"));
492         ErrorCatcher catcher (pyError);
493         sysModule.attr("stderr") = catcher;
494
495         py::object initModule (py::import("init"));
496         impl_->mainNamespace = py::extract<py::dict>(initModule.attr("__dict__"));
497         impl_->pythonPublisher = py::extract<Publisher*>(impl_->mainNamespace["initialize"]());
498
499         sysModule.attr("stderr") = origStderr;
500     }
501     catch (boost::python::error_already_set & ex) {
502         PyErr_Print();
503         throw PythonError(pyError);
504     }
505 }
506
507 prefix_ pykit::PythonPublisher::~PythonPublisher()
508 {
509     try {
510         impl_->mainNamespace["shutdown"]();
511     }
512     catch (...) {;}
513 }
514
515 prefix_ void pykit::PythonPublisher::publish(Request & request)
516 {
517     try {
518         impl_->pythonPublisher->publish(request);
519     }
520     catch (py::error_already_set & ex) {
521         PyErr_Print();
522         PyErr_Clear();
523     }
524 }
525
526 ///////////////////////////////cc.e////////////////////////////////////////
527 #undef prefix_
528 //#include "PythonPublisher.mpp"
529
530 \f
531 // Local Variables:
532 // mode: c++
533 // fill-column: 100
534 // comment-column: 40
535 // c-file-style: "j32"
536 // indent-tabs-mode: nil
537 // ispell-local-dictionary: "american"
538 // compile-command: "scons -U"
539 // End: