]> git.saurik.com Git - wxWidgets.git/blame - wxPython/contrib/activex/activex.i
reSWIGged
[wxWidgets.git] / wxPython / contrib / activex / activex.i
CommitLineData
b7c75283
RD
1/////////////////////////////////////////////////////////////////////////////
2// Name: activex.i
3// Purpose: ActiveX controls (such as Internet Explorer) in a wxWindow
4//
5// Author: Robin Dunn
6//
7// Created: 18-Mar-2004
8// RCS-ID: $Id$
9// Copyright: (c) 2004 by Total Control Software
10// Licence: wxWindows license
11/////////////////////////////////////////////////////////////////////////////
12
13
b2eb030f 14%module(package="wx") activex
b7c75283
RD
15
16%{
17#include "wx/wxPython/wxPython.h"
18#include "wx/wxPython/pyclasses.h"
19#include "wx/wxPython/pyistream.h"
20
21#include "wxactivex.h"
22%}
23
24//---------------------------------------------------------------------------
25
26%import core.i
54f9ee45 27%pythoncode { wx = _core }
99109c0f 28%pythoncode { __docfilter__ = wx.__DocFilter(globals()) }
b7c75283
RD
29
30MAKE_CONST_WXSTRING_NOSWIG(PanelNameStr);
31
b7c75283
RD
32
33//---------------------------------------------------------------------------
34
35typedef unsigned short USHORT;
36typedef long DISPID;
37typedef long MEMBERID;
38typedef unsigned short VARTYPE;
39
40
41%{
42// Since SWIG doesn't support nested classes, we need to fool it a bit
43// and make them look like global classes. These defines make the C++ code
44// know what we are doing.
45#define wxParamX wxActiveX::ParamX
46#define wxFuncX wxActiveX::FuncX
47#define wxPropX wxActiveX::PropX
48#define wxParamXArray wxActiveX::ParamXArray
49#define wxFuncXArray wxActiveX::FuncXArray
50#define wxPropXArray wxActiveX::PropXArray
51%}
52
53
54%{
55// Some conversion helpers
56static wxVariant _PyObj2Variant(PyObject* value);
0dabb2a2 57static bool _PyObj2Variant(PyObject* value, wxVariant& wv);
a72f4631 58static PyObject* _Variant2PyObj(wxVariant& value, bool useNone=false);
b7c75283
RD
59static wxString _VARTYPEname(VARTYPE vt);
60
61// Check if an exception has been raised (blocking threads)
62inline bool wxPyErr_Occurred()
63{
64 bool rval;
6e6b3557 65 wxPyBlock_t blocked = wxPyBeginBlockThreads();
b7c75283 66 rval = PyErr_Occurred() != NULL;
0dabb2a2 67 wxPyEndBlockThreads(blocked);
b7c75283
RD
68 return rval;
69}
70
71%}
72
73//---------------------------------------------------------------------------
74%newgroup
75
76DocStr(CLSID,
77"This class wraps the Windows CLSID structure and is used to
78specify the class of the ActiveX object that is to be created. A
79CLSID can be constructed from either a ProgID string, (such as
80'WordPad.Document.1') or a classID string, (such as
6cfd7f95 81'{CA8A9783-280D-11CF-A24D-444553540000}').", "");
b7c75283
RD
82
83class CLSID {
84public:
85 %extend {
86 CLSID(const wxString& id)
87 {
88 int result;
89 CLSID* self = new CLSID;
90 memset(self, 0, sizeof(CLSID));
91
92 if (id[0] == _T('{')) {
93 // Looks like a classID string
94 result =
95 CLSIDFromString(
96 (LPOLESTR)(const wchar_t *)id.wc_str(wxConvUTF8),
97 self);
98 } else {
99 // Try a progID
100 result =
101 CLSIDFromProgID(
102 (LPOLESTR)(const wchar_t *)id.wc_str(wxConvUTF8),
103 self);
104 }
105 if (result != NOERROR) {
106 wxPyErr_SetString(PyExc_ValueError, "Not a recognized classID or progID");
107 delete self;
108 return NULL;
109 }
110 return self;
111 }
112
113 ~CLSID() { delete self; }
114
115 wxString GetCLSIDString()
116 {
117 LPOLESTR s;
118 wxString str;
119 if (StringFromCLSID(*self, &s) == S_OK) {
120 str = s;
121 CoTaskMemFree(s);
122 }
123 else {
124 str = _T("Error!"); // TODO: raise exception?
125 }
126 return str;
127 }
128 wxString GetProgIDString()
129 {
130 LPOLESTR s;
131 wxString str;
132 if (ProgIDFromCLSID(*self, &s) == S_OK) {
133 str = s;
134 CoTaskMemFree(s);
135 }
136 else {
137 str = _T("Error!"); // TODO: raise exception?
138 }
139 return str;
140 }
141 }
142 %pythoncode { def __str__(self): return self.GetCLSIDString() }
143};
144
145
146//---------------------------------------------------------------------------
147%newgroup
148
149%define MAKE_ARRAY_WRAPPER(basetype, arrayname)
150class arrayname
151{
152public:
153 %extend {
154 bool __nonzero__() { return self->size() > 0; }
155 int __len__() { return self->size(); }
156
157 const basetype& __getitem__(int idx) {
158 if ( idx >= 0 && idx < self->size() )
159 return (*self)[idx];
160 else {
161 static basetype BadVal;
162 wxPyErr_SetString(PyExc_IndexError, "Index out of range");
163 return BadVal;
164 }
165 }
166 // TODO __iter__??
167 }
168};
169%enddef
170
171//---------------------------------------------------------------------------
172
173%immutable;
174
175class wxParamX
176{
177public:
178 USHORT flags;
179 bool isPtr;
180 bool isSafeArray;
181 bool isOptional;
182 VARTYPE vt;
183 wxString name;
184
185 %feature("shadow") vt_type_get "vt_type = property(_activex.ParamX_vt_type_get)";
186 %extend { wxString vt_type_get() { return _VARTYPEname(self->vt); } }
187
188 %feature("shadow") IsIn "isIn = property(_activex.ParamX_IsIn)";
189 %feature("shadow") IsOut "isOut = property(_activex.ParamX_IsOut)";
190 %feature("shadow") IsRetVal "isRetVal = property(_activex.ParamX_IsRetVal)";
191 bool IsIn() const;
192 bool IsOut() const;
193 bool IsRetVal() const;
194
195};
196
197
198class wxFuncX
199{
200public:
201 wxString name;
202 MEMBERID memid;
203 bool hasOut;
204
205 wxParamX retType;
206 wxParamXArray params;
207};
208
209
210class wxPropX
211{
212public:
213 wxString name;
214 MEMBERID memid;
215 wxParamX type;
216 wxParamX arg;
217 bool putByRef;
218
219 %feature("shadow") CanGet "canGet = property(_activex.PropX_CanGet)";
220 %feature("shadow") CanSet "canSet = property(_activex.PropX_CanSet)";
221 bool CanGet() const;
222 bool CanSet() const;
223};
224%mutable;
225
226
227MAKE_ARRAY_WRAPPER(wxParamX, wxParamXArray);
228MAKE_ARRAY_WRAPPER(wxFuncX, wxFuncXArray);
229MAKE_ARRAY_WRAPPER(wxPropX, wxPropXArray);
230
231
232//---------------------------------------------------------------------------
233%newgroup
234
235%{
236// C++ version of a Python-aware wxActiveX
237class wxActiveXWindow : public wxActiveX
238{
239private:
240 CLSID m_CLSID;
a8f72945
RD
241
242 DECLARE_ABSTRACT_CLASS(wxActiveXWindow);
243
b7c75283
RD
244public:
245 wxActiveXWindow( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
246 const wxPoint& pos = wxDefaultPosition,
247 const wxSize& size = wxDefaultSize,
248 long style = 0,
249 const wxString& name = wxPyPanelNameStr)
250 : wxActiveX(parent, clsId, id, pos, size, style, name)
251 {
252 m_CLSID = clsId;
253 }
254
255 const CLSID& GetCLSID() const { return m_CLSID; }
256
257
258 // Renamed versions of some base class methods that delegate
259 // to the base where appropriate, and raise Python exceptions
260 // when needed.
261 int GetAXEventCount() const { return wxActiveX::GetEventCount(); }
262 int GetAXPropCount() const { return wxActiveX::GetPropCount(); }
263 int GetAXMethodCount() const { return wxActiveX::GetMethodCount(); }
264
265 const wxFuncX& GetAXEventDesc(int idx) const
266 {
267 static wxFuncX BadVal;
268 if (idx < 0 || idx >= GetAXEventCount()) {
269 wxPyErr_SetString(PyExc_IndexError, "Index out of range");
270 return BadVal;
271 }
272 return m_events[idx];
273 }
274 const wxFuncX& GetAXMethodDesc(int idx) const
275 {
276 static wxFuncX BadVal;
277 if (idx < 0 || idx >= GetAXMethodCount()) {
278 wxPyErr_SetString(PyExc_IndexError, "Index out of range");
279 return BadVal;
280 }
281 return m_methods[idx];
282 }
283 const wxPropX& GetAXPropDesc(int idx) const
284 {
285 static wxPropX BadVal;
286 if (idx < 0 || idx >= GetAXPropCount()) {
287 wxPyErr_SetString(PyExc_IndexError, "Index out of range");
288 return BadVal;
289 }
290 return m_props[idx];
291 }
292
293 const wxFuncX& GetAXMethodDesc(const wxString& name) const
294 {
295 NameMap::const_iterator it = m_methodNames.find(name);
296 if (it == m_methodNames.end()) {
297 wxString msg;
0dabb2a2 298 msg << _T("method <") << name << _T("> not found");
b7c75283
RD
299 wxPyErr_SetString(PyExc_KeyError, msg.mb_str());
300 static wxFuncX BadVal;
301 return BadVal;
302 };
303 return GetAXMethodDesc(it->second);
304 }
305 const wxPropX& GetAXPropDesc(const wxString& name) const
306 {
307 NameMap::const_iterator it = m_propNames.find(name);
308 if (it == m_propNames.end()) {
309 wxString msg;
0dabb2a2 310 msg << _T("property <") << name << _T("> not found");
b7c75283
RD
311 wxPyErr_SetString(PyExc_KeyError, msg.mb_str());
312 static wxPropX BadVal;
313 return BadVal;
314 };
315 return GetAXPropDesc(it->second);
316 }
317
318 // Accessors for the internal vectors of events, methods and
319 // proprties. Can be used as sequence like objects from
320 // Python.
321 const wxFuncXArray& GetAXEvents() { return m_events; }
322 const wxFuncXArray& GetAXMethods() { return m_methods; }
323 const wxPropXArray& GetAXProperties() { return m_props; }
324
325
326 // Set a property from a Python object
327 void SetAXProp(const wxString& name, PyObject* value)
328 {
329 const wxPropX& prop = GetAXPropDesc(name);
6e6b3557 330 wxPyBlock_t blocked = wxPyBeginBlockThreads();
b7c75283
RD
331 if (! PyErr_Occurred() ) {
332 if (! prop.CanSet()) {
333 wxString msg;
0dabb2a2 334 msg << _T("property <") << name << _T("> is readonly");
b7c75283
RD
335 PyErr_SetString(PyExc_TypeError, msg.mb_str());
336 goto done;
337 } else {
338 wxVariant wxV = _PyObj2Variant(value);
339 if (PyErr_Occurred())
340 goto done;
341 VARIANT v = {prop.arg.vt};
342 if (!VariantToMSWVariant(wxV, v) || PyErr_Occurred()) {
343 wxString msg;
0dabb2a2
RD
344 msg << _T("Unable to convert value to expected type: (")
345 << _VARTYPEname(prop.arg.vt) << _T(") for property <")
346 << name << _T(">");
b7c75283
RD
347 PyErr_SetString(PyExc_TypeError, msg.mb_str());
348 goto done;
349 }
350 PyThreadState* tstate = wxPyBeginAllowThreads();
351 SetProp(prop.memid, v);
352 VariantClear(&v);
353 wxPyEndAllowThreads(tstate);
354 }
355 }
356 done:
0dabb2a2 357 wxPyEndBlockThreads(blocked);
b7c75283
RD
358 }
359
360
361 // Get a property and convert it to a Python object
362 PyObject* GetAXProp(const wxString& name)
363 {
364 PyObject* rval = NULL;
365 const wxPropX& prop = GetAXPropDesc(name);
6e6b3557 366 wxPyBlock_t blocked = wxPyBeginBlockThreads();
b7c75283
RD
367 if (! PyErr_Occurred() ) {
368 if (! prop.CanGet()) {
369 wxString msg;
0dabb2a2 370 msg << _T("property <") << name << _T("> is writeonly");
b7c75283
RD
371 PyErr_SetString(PyExc_TypeError, msg.mb_str());
372 goto done;
373 } else {
374 PyThreadState* tstate = wxPyBeginAllowThreads();
375 VARIANT v = GetPropAsVariant(prop.memid);
376 wxPyEndAllowThreads(tstate);
377 wxVariant wv;
378 if (!MSWVariantToVariant(v, wv) || PyErr_Occurred()) {
379 wxString msg;
0dabb2a2
RD
380 msg << _T("Unable to convert value to expected type: (")
381 << _VARTYPEname(prop.arg.vt) << _T(") for property <")
382 << name << _T(">");
b7c75283
RD
383 PyErr_SetString(PyExc_TypeError, msg.mb_str());
384 goto done;
385 }
386 rval = _Variant2PyObj(wv);
387 VariantClear(&v);
388 }
389 }
390 done:
0dabb2a2 391 wxPyEndBlockThreads(blocked);
b7c75283
RD
392 return rval;
393 }
394
395
396 // If both IsIn and isOut are false, assume it is actually an
397 // input param
398 bool paramIsIn(const wxParamX& p)
399 {
400 return p.IsIn() || (!p.IsIn() && !p.IsOut());
401 }
402
403
404 // Call a method of the ActiveX object
405 PyObject* _CallAXMethod(const wxString& name, PyObject* args)
406 {
407 VARIANTARG *vargs = NULL;
408 int nargs = 0;
409 PyObject* rval = NULL;
410 const wxFuncX& func = GetAXMethodDesc(name);
411
6e6b3557 412 wxPyBlock_t blocked = wxPyBeginBlockThreads();
b7c75283
RD
413 if (! PyErr_Occurred() ) {
414 nargs = func.params.size();
415 if (nargs > 0)
416 vargs = new VARIANTARG[nargs];
417
418 if (vargs) {
419 // init type of vargs, in reverse order
420 int i;
421 for (i = 0; i < nargs; i++)
422 vargs[nargs - i - 1].vt = func.params[i].vt;
423
424 // Map the args coming from Python to the input parameters in vargs
425 int pi = 0;
426 i = 0;
427 while ( i<nargs && pi<PyTuple_Size(args) ) {
428 // Move to the next input param.
429 if (! paramIsIn(func.params[i])) {
430 i += 1;
431 continue;
432 }
433 // convert the python object
434 PyObject* obj = PyTuple_GetItem(args, pi);
435 if (obj == Py_None) // special-case None?
436 vargs[nargs - i - 1].vt = VT_EMPTY;
437 else {
438 wxVariant wxV = _PyObj2Variant(obj);
439 if (PyErr_Occurred())
440 goto done;
441 if (!VariantToMSWVariant(wxV, vargs[nargs - i - 1]) || PyErr_Occurred()) {
442 wxString msg;
0dabb2a2 443 msg << _T("Unable to convert value to expected type: (")
b7c75283 444 << _VARTYPEname(vargs[nargs - i - 1].vt)
0dabb2a2 445 << _T(") for parameter ") << i;
b7c75283
RD
446 PyErr_SetString(PyExc_TypeError, msg.mb_str());
447 goto done;
448 }
449 }
450 i += 1;
451 pi += 1;
452 }
453 }
454
455 // call the method
456 PyThreadState* tstate = wxPyBeginAllowThreads();
457 VARIANT rv = CallMethod(func.memid, vargs, nargs);
458 wxPyEndAllowThreads(tstate);
459
460 // Convert the return value and any out-params, ignoring
461 // conversion errors for now
462 wxVariant wv;
463 MSWVariantToVariant(rv, wv);
a72f4631 464 rval = _Variant2PyObj(wv, true);
b7c75283
RD
465 VariantClear(&rv);
466
467 if (func.hasOut) {
468 // make a list and put the rval in it if it is not None
469 PyObject* lst = PyList_New(0);
470 if (rval != Py_None)
471 PyList_Append(lst, rval);
472 else
473 Py_DECREF(rval);
474
475 // find the out params and convert them
476 for (int i = 0; i < nargs; i++) {
477 VARIANTARG& va = vargs[nargs - i - 1];
478 const wxParamX &px = func.params[i];
479 if (px.IsOut()) {
480 MSWVariantToVariant(va, wv);
a72f4631 481 PyObject* obj = _Variant2PyObj(wv, true);
b7c75283
RD
482 PyList_Append(lst, obj);
483 }
484 }
485 rval = PyList_AsTuple(lst);
486 Py_DECREF(lst);
487 }
488 if (PyErr_Occurred())
489 PyErr_Clear();
490 }
491 done:
0dabb2a2 492 wxPyEndBlockThreads(blocked);
b7c75283
RD
493 if (vargs) {
494 for (int i = 0; i < nargs; i++)
495 VariantClear(&vargs[i]);
496 delete [] vargs;
497 }
498 return rval;
499 }
500};
a8f72945
RD
501
502IMPLEMENT_ABSTRACT_CLASS( wxActiveXWindow, wxWindow );
b7c75283
RD
503%}
504
505
506
507// Now tell SWIG about this new class that is implemented above.
508
509DocStr(wxActiveXWindow,
510"ActiveXWindow derives from wxWindow and the constructor accepts a
511CLSID for the ActiveX Control that should be created. The
512ActiveXWindow class simply adds methods that allow you to query
513some of the TypeInfo exposed by the ActiveX object, and also to
514get/set properties or call methods by name. The Python
515implementation automatically handles converting parameters and
516return values to/from the types expected by the ActiveX code as
517specified by the TypeInfo.
6cfd7f95 518", "");
b7c75283
RD
519
520
ab1f7d2a
RD
521MustHaveApp(wxActiveXWindow);
522
b7c75283
RD
523class wxActiveXWindow : public wxWindow
524{
525public:
526 %pythonAppend wxActiveXWindow "self._setOORInfo(self)"
527
528 DocCtorStr(
529 wxActiveXWindow( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
530 const wxPoint& pos = wxDefaultPosition,
531 const wxSize& size = wxDefaultSize,
532 long style = 0,
533 const wxString& name = wxPyPanelNameStr),
534 "Creates an ActiveX control from the clsID given and makes it act
6cfd7f95 535as much like a regular wx.Window as possible.", "");
b7c75283
RD
536
537 DocDeclStr(
538 const CLSID& , GetCLSID() const,
6cfd7f95 539 "Return the CLSID used to construct this ActiveX window", "");
b7c75283
RD
540
541
542 DocDeclStr(
543 int , GetAXEventCount() const,
6cfd7f95 544 "Number of events defined for this control", "");
b7c75283
RD
545
546 DocDeclStr(
547 const wxFuncX& , GetAXEventDesc(int idx) const,
6cfd7f95 548 "Returns event description by index", "");
b7c75283
RD
549
550
551 DocDeclStr(
552 int , GetAXPropCount() const,
6cfd7f95 553 "Number of properties defined for this control", "");
b7c75283
RD
554
555 %nokwargs GetAXPropDesc;
6cfd7f95 556 DocStr(GetPropDesc, "Returns property description by index or by name", "");
b7c75283
RD
557 const wxPropX& GetAXPropDesc(int idx) const;
558 const wxPropX& GetAXPropDesc(const wxString& name) const;
559
560
561
562 DocDeclStr(
563 int , GetAXMethodCount() const,
6cfd7f95 564 "Number of methods defined for this control", "");
b7c75283
RD
565
566 %nokwargs GetAXMethodDesc;
6cfd7f95 567 DocStr(GetMethodDesc, "Returns method description by index or name", "");
b7c75283
RD
568 const wxFuncX& GetAXMethodDesc(int idx) const;
569 const wxFuncX& GetAXMethodDesc(const wxString& name) const;
570
571
572 DocDeclStr(
573 const wxFuncXArray& , GetAXEvents(),
574 "Returns a sequence of FuncX objects describing the events
6cfd7f95 575available for this ActiveX object.", "");
b7c75283
RD
576
577 DocDeclStr(
578 const wxFuncXArray& , GetAXMethods(),
579 "Returns a sequence of FuncX objects describing the methods
6cfd7f95 580available for this ActiveX object.", "");
b7c75283
RD
581
582 DocDeclStr(
583 const wxPropXArray& , GetAXProperties(),
584 "Returns a sequence of PropX objects describing the properties
6cfd7f95 585available for this ActiveX object.", "");
b7c75283
RD
586
587
588
589 DocDeclStr(
590 void , SetAXProp(const wxString& name, PyObject* value),
6cfd7f95 591 "Set a property of the ActiveX object by name.", "");
b7c75283
RD
592
593
594 DocDeclStr(
595 PyObject* , GetAXProp(const wxString& name),
6cfd7f95 596 "Get the value of an ActiveX property by name.", "");
b7c75283
RD
597
598
599 %nokwargs _CallAXMethod;
600 DocDeclStr(
601 PyObject* , _CallAXMethod(const wxString& name, PyObject* args),
602 "The implementation for CallMethod. Calls an ActiveX method, by
6cfd7f95 603name passing the parameters given in args.", "");
b7c75283
RD
604 %pythoncode {
605 def CallAXMethod(self, name, *args):
606 """
607 Front-end for _CallMethod. Simply passes all positional args
608 after the name as a single tuple to _CallMethod.
609 """
610 return self._CallAXMethod(name, args)
611 }
612};
613
614//---------------------------------------------------------------------------
615%newgroup
616
617DocDeclStr(
618 wxEventType , RegisterActiveXEvent(const wxString& eventName),
6cfd7f95 619 "Creates a standard wx event ID for the given eventName.", "");
b7c75283
RD
620
621
622
623DocStr(wxActiveXEvent,
624"An instance of ActiveXEvent is sent to the handler for all bound
625ActiveX events. Any event parameters from the ActiveX cntrol are
626turned into attributes of the Python proxy for this event object.
627Additionally, there is a property called eventName that will
6cfd7f95 628return (surprisingly <wink>) the name of the ActiveX event.", "");
b7c75283
RD
629
630class wxActiveXEvent : public wxCommandEvent
631{
632public:
633 %feature("shadow") EventName "eventName = property(_activex.ActiveXEvent_EventName)";
634 wxString EventName();
635
636 %extend {
0dabb2a2
RD
637
638 // This is called by the EventThunker before calling the
639 // handler. We'll convert and load the ActiveX event parameters into
640 // attributes of the Python event object.
641 void _preCallInit(PyObject* pyself) {
6e6b3557 642 wxPyBlock_t blocked = wxPyBeginBlockThreads();
b7c75283
RD
643 PyObject* pList = PyList_New(0);
644 PyObject_SetAttrString(pyself, "paramList", pList);
645 Py_DECREF(pList);
646 for (int i=0; i<self->ParamCount(); i+=1) {
0dabb2a2 647 PyObject* name = PyString_FromString((char*)(const char*)self->ParamName(i).mb_str());
a72f4631 648 PyObject* val = _Variant2PyObj((*self)[i], true);
b7c75283
RD
649 PyObject_SetAttr(pyself, name, val);
650 PyList_Append(pList, name);
651 Py_DECREF(val);
652 Py_DECREF(name);
653 }
0dabb2a2
RD
654 wxPyEndBlockThreads(blocked);
655 }
656
657 // This one is called by the EventThunker after calling the
658 // handler. It reloads any "out" parameters from the python attributes
659 // back into the wxVariant they came from.
660 void _postCallCleanup(PyObject* pyself) {
6e6b3557 661 wxPyBlock_t blocked = wxPyBeginBlockThreads();
0dabb2a2
RD
662 for (int i=0; i<self->ParamCount(); i+=1) {
663 PyObject* val = PyObject_GetAttrString(
664 pyself, (char*)(const char*)self->ParamName(i).mb_str());
665 _PyObj2Variant(val, (*self)[i]);
666 Py_DECREF(val);
667 }
668 wxPyEndBlockThreads(blocked);
b7c75283 669 }
0dabb2a2
RD
670
671
b7c75283
RD
672 }
673};
674
675//---------------------------------------------------------------------------
676
677%{
678
679// Caller should already have the GIL!
680wxVariant _PyObj2Variant(PyObject* value)
681{
682 wxVariant rval;
683
684 if (value == Py_None)
685 return rval;
686
0dabb2a2 687#if PYTHON_API_VERSION >= 1012 // Python 2.3+
b7c75283
RD
688 else if (PyBool_Check(value))
689 rval = (value == Py_True) ? true : false;
0dabb2a2
RD
690#endif
691
b7c75283
RD
692 else if (PyInt_Check(value))
693 rval = PyInt_AS_LONG(value);
694
695 else if (PyFloat_Check(value))
696 rval = PyFloat_AS_DOUBLE(value);
697
698 else if (PyString_Check(value) || PyUnicode_Check(value))
699 rval = Py2wxString(value);
700
701 // TODO: PyList of strings --> wxArrayString
702 // wxDateTime
703 // list of objects
0dabb2a2 704 // etc.
b7c75283
RD
705
706 else {
707 PyErr_SetString(PyExc_TypeError, "Unsupported object type in _PyObj2Variant");
708 rval = (long)0;
709 }
710
711 return rval;
712}
713
0dabb2a2
RD
714// This one uses the type of the variant to try and force the conversion
715bool _PyObj2Variant(PyObject* value, wxVariant& wv)
716{
717 wxString type = wv.GetType();
718
719 if ( type == _T("long") || type == _T("bool") || type == _T("char") )
720 wv = PyInt_AsLong(value);
721
722 else if ( type == _T("string") )
723 wv = Py2wxString(value);
724
725 else if ( type == _T("double") )
726 wv = PyFloat_AsDouble(value);
727
728 else {
729 // it's some other type that we dont' handle yet. Log it?
730 return false;
731 }
732 return true;
733}
b7c75283
RD
734
735// Caller should already have the GIL!
736PyObject* _Variant2PyObj(wxVariant& value, bool useNone)
737{
738 PyObject* rval = NULL;
739
740 if (value.IsNull()) {
741 rval = Py_None;
742 Py_INCREF(rval);
743 }
744
745 // should "char" be treated as an int or as a string?
746 else if (value.IsType(_T("char")) || value.IsType(_T("long")))
747 rval = PyInt_FromLong(value);
748
749 else if (value.IsType(_T("double")))
750 rval = PyFloat_FromDouble(value);
751
0dabb2a2
RD
752 else if (value.IsType(_T("bool"))) {
753 rval = (bool)value ? Py_True : Py_False;
754 Py_INCREF(rval);
755 }
b7c75283
RD
756
757 else if (value.IsType(_T("string")))
758 rval = wx2PyString(value);
759
760 else {
761 if (useNone) {
762 rval = Py_None;
763 Py_INCREF(rval);
764 }
765 else {
766 PyErr_SetString(PyExc_TypeError, "Unsupported object type in _Variant2PyObj");
767 }
768 }
769 return rval;
770}
771
772
773wxString _VARTYPEname(VARTYPE vt)
774{
775 if (vt & VT_BYREF)
776 vt &= ~(VT_BYREF);
777
778 switch(vt) {
779 case VT_VARIANT:
780 return _T("VT_VARIANT");
781
782 // 1 byte chars
783 case VT_I1:
784 case VT_UI1:
785 // 2 byte shorts
786 case VT_I2:
787 case VT_UI2:
788 // 4 bytes longs
789 case VT_I4:
790 case VT_UI4:
791 case VT_INT:
792 case VT_UINT:
793 case VT_ERROR:
794 return _T("int");
795
796 // 4 byte floats
797 case VT_R4:
798 // 8 byte doubles
799 case VT_R8:
800 // decimals are converted from doubles too
801 case VT_DECIMAL:
802 return _T("double");
803
804 case VT_BOOL:
805 return _T("bool");
806
807 case VT_DATE:
808 return _T("wx.DateTime");
809
810 case VT_BSTR:
811 return _T("string");
812
813 case VT_UNKNOWN:
814 return _T("VT_UNKNOWN");
815
816 case VT_DISPATCH:
817 return _T("VT_DISPATCH");
818
819 case VT_EMPTY:
820 return _T("VT_EMPTY");
821
822 case VT_NULL:
823 return _T("VT_NULL");
824
825 case VT_VOID:
826 return _T("VT_VOID");
827
828 default:
829 wxString msg;
830 msg << _T("unsupported type ") << vt;
831 return msg;
832 }
833}
834
835%}
836
837//---------------------------------------------------------------------------
838//---------------------------------------------------------------------------
839%newgroup
840
841
842%{
1069efb9 843// A class derived from our wxActiveXWindow for the IE WebBrowser
b7c75283
RD
844// control that will serve as a base class for a Python
845// implementation. This is done so we can "eat our own dog food"
846// and use a class at least mostly generated by genaxmodule, but
847// also get some of the extra stuff like loading a document from
848// a string or a stream, getting text contents, etc. that
849// Lindsay's version gives us.
850//
851
852#include <wx/mstream.h>
853#include <oleidl.h>
854#include <winerror.h>
855#include <exdispid.h>
856#include <exdisp.h>
857#include <olectl.h>
858#include <Mshtml.h>
859#include <sstream>
860
861#include "IEHtmlStream.h"
862
863class wxIEHtmlWindowBase : public wxActiveXWindow {
864private:
865 wxAutoOleInterface<IWebBrowser2> m_webBrowser;
866
a8f72945
RD
867 DECLARE_ABSTRACT_CLASS(wxIEHtmlWindowBase);
868
b7c75283
RD
869public:
870
871 wxIEHtmlWindowBase ( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
872 const wxPoint& pos = wxDefaultPosition,
873 const wxSize& size = wxDefaultSize,
874 long style = 0,
875 const wxString& name = wxPyPanelNameStr)
876 : wxActiveXWindow(parent, clsId, id, pos, size, style, name)
877 {
878 HRESULT hret;
879
880 // Get IWebBrowser2 Interface
881 hret = m_webBrowser.QueryInterface(IID_IWebBrowser2, m_ActiveX);
83cbb9e9
RD
882 wxASSERT(SUCCEEDED(hret));
883
884 // web browser setup
885 m_webBrowser->put_MenuBar(VARIANT_FALSE);
886 m_webBrowser->put_AddressBar(VARIANT_FALSE);
887 m_webBrowser->put_StatusBar(VARIANT_FALSE);
888 m_webBrowser->put_ToolBar(VARIANT_FALSE);
889
890 m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
891 m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
892
893 m_webBrowser->Navigate( L"about:blank", NULL, NULL, NULL, NULL );
b7c75283
RD
894 }
895
896
897 void SetCharset(const wxString& charset)
898 {
899 HRESULT hret;
900
901 // HTML Document ?
902 IDispatch *pDisp = NULL;
903 hret = m_webBrowser->get_Document(&pDisp);
904 wxAutoOleInterface<IDispatch> disp(pDisp);
905
906 if (disp.Ok())
907 {
908 wxAutoOleInterface<IHTMLDocument2> doc(IID_IHTMLDocument2, disp);
909 if (doc.Ok())
910 doc->put_charset((BSTR) (const wchar_t *) charset.wc_str(wxConvUTF8));
911 //doc->put_charset((BSTR) wxConvUTF8.cMB2WC(charset).data());
912 }
913 }
914
915
916 bool LoadString(const wxString& html)
917 {
918 char *data = NULL;
919 size_t len = html.length();
920 len *= sizeof(wxChar);
921 data = (char *) malloc(len);
922 memcpy(data, html.c_str(), len);
923 return LoadStream(new wxOwnedMemInputStream(data, len));
924 }
925
926
927 bool LoadStream(IStreamAdaptorBase *pstrm)
928 {
929 // need to prepend this as poxy MSHTML will not recognise a HTML comment
930 // as starting a html document and treats it as plain text
931 // Does nayone know how to force it to html mode ?
0dabb2a2
RD
932#if wxUSE_UNICODE
933 // TODO: What to do in this case???
934#else
935 pstrm->prepend = _T("<html>");
936#endif
b7c75283
RD
937
938 // strip leading whitespace as it can confuse MSHTML
939 wxAutoOleInterface<IStream> strm(pstrm);
940
941 // Document Interface
942 IDispatch *pDisp = NULL;
943 HRESULT hret = m_webBrowser->get_Document(&pDisp);
944 if (! pDisp)
945 return false;
946 wxAutoOleInterface<IDispatch> disp(pDisp);
947
948
949 // get IPersistStreamInit
950 wxAutoOleInterface<IPersistStreamInit>
951 pPersistStreamInit(IID_IPersistStreamInit, disp);
952
953 if (pPersistStreamInit.Ok())
954 {
955 HRESULT hr = pPersistStreamInit->InitNew();
956 if (SUCCEEDED(hr))
957 hr = pPersistStreamInit->Load(strm);
958
959 return SUCCEEDED(hr);
960 }
961 else
962 return false;
963 }
964
965 bool LoadStream(wxInputStream *is)
966 {
967 // wrap reference around stream
968 IwxStreamAdaptor *pstrm = new IwxStreamAdaptor(is);
969 pstrm->AddRef();
970
971 return LoadStream(pstrm);
972 }
973
974
975 wxString GetStringSelection(bool asHTML)
976 {
977 wxAutoOleInterface<IHTMLTxtRange> tr(wxieGetSelRange(m_oleObject));
978 if (! tr)
979 return wxEmptyString;
980
981 BSTR text = NULL;
982 HRESULT hr = E_FAIL;
983
984 if (asHTML)
985 hr = tr->get_htmlText(&text);
986 else
987 hr = tr->get_text(&text);
988 if (hr != S_OK)
989 return wxEmptyString;
990
991 wxString s = text;
992 SysFreeString(text);
993
994 return s;
995 };
996
997 wxString GetText(bool asHTML)
998 {
999 if (! m_webBrowser.Ok())
1000 return wxEmptyString;
1001
1002 // get document dispatch interface
1003 IDispatch *iDisp = NULL;
1004 HRESULT hr = m_webBrowser->get_Document(&iDisp);
1005 if (hr != S_OK)
1006 return wxEmptyString;
1007
1008 // Query for Document Interface
1009 wxAutoOleInterface<IHTMLDocument2> hd(IID_IHTMLDocument2, iDisp);
1010 iDisp->Release();
1011
1012 if (! hd.Ok())
1013 return wxEmptyString;
1014
1015 // get body element
1016 IHTMLElement *_body = NULL;
1017 hd->get_body(&_body);
1018 if (! _body)
1019 return wxEmptyString;
1020 wxAutoOleInterface<IHTMLElement> body(_body);
1021
1022 // get inner text
1023 BSTR text = NULL;
1024 hr = E_FAIL;
1025
1026 if (asHTML)
1027 hr = body->get_innerHTML(&text);
1028 else
1029 hr = body->get_innerText(&text);
1030 if (hr != S_OK)
1031 return wxEmptyString;
1032
1033 wxString s = text;
1034 SysFreeString(text);
1035
1036 return s;
1037 }
1038
1039
1040// void wxIEHtmlWin::SetEditMode(bool seton)
1041// {
1042// m_bAmbientUserMode = ! seton;
1043// AmbientPropertyChanged(DISPID_AMBIENT_USERMODE);
1044// };
1045
1046// bool wxIEHtmlWin::GetEditMode()
1047// {
1048// return ! m_bAmbientUserMode;
1049// };
1050};
a8f72945
RD
1051
1052IMPLEMENT_ABSTRACT_CLASS( wxIEHtmlWindowBase, wxActiveXWindow );
1053
b7c75283
RD
1054%}
1055
1056
1057// we'll document it in the derived Python class
1058%feature("noautodoc") wxIEHtmlWindowBase;
1059%feature("noautodoc") wxIEHtmlWindowBase::SetCharset;
1060%feature("noautodoc") wxIEHtmlWindowBase::LoadString;
1061%feature("noautodoc") wxIEHtmlWindowBase::LoadStream;
1062%feature("noautodoc") wxIEHtmlWindowBase::GetStringSelection;
1063%feature("noautodoc") wxIEHtmlWindowBase::GetText;
1064
1065
ab1f7d2a
RD
1066MustHaveApp(wxIEHtmlWindowBase);
1067
b7c75283
RD
1068class wxIEHtmlWindowBase : public wxActiveXWindow {
1069public:
a8f72945 1070 %pythonAppend wxIEHtmlWindowBase "self._setOORInfo(self)"
b7c75283
RD
1071
1072 wxIEHtmlWindowBase ( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
1073 const wxPoint& pos = wxDefaultPosition,
1074 const wxSize& size = wxDefaultSize,
1075 long style = 0,
1076 const wxString& name = wxPyPanelNameStr);
1077
1078 void SetCharset(const wxString& charset);
1079 bool LoadString(const wxString& html);
1080 bool LoadStream(wxInputStream *is);
1081 wxString GetStringSelection(bool asHTML);
1082 wxString GetText(bool asHTML);
1083};
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095#if 0
1096enum wxIEHtmlRefreshLevel
1097{
1098 wxIEHTML_REFRESH_NORMAL = 0,
1099 wxIEHTML_REFRESH_IFEXPIRED = 1,
1100 wxIEHTML_REFRESH_CONTINUE = 2,
1101 wxIEHTML_REFRESH_COMPLETELY = 3
1102};
1103
1104DocStr(wxIEHtmlWin,
1105"");
1106class wxIEHtmlWin : public wxWindow
1107{
1108public:
1109 %pythonAppend wxIEHtmlWin "self._setOORInfo(self)"
1110
1111 wxIEHtmlWin(wxWindow * parent, wxWindowID id = -1,
1112 const wxPoint& pos = wxDefaultPosition,
1113 const wxSize& size = wxDefaultSize,
1114 long style = 0,
1115 const wxString& name = wxPyPanelNameStr);
1116
1117 void LoadUrl(const wxString& url);
1118 bool LoadString(wxString html);
1119 bool LoadStream(wxInputStream *is);
1120
1121 %pythoncode { Navigate = LoadUrl }
1122
1123 void SetCharset(wxString charset);
1124 void SetEditMode(bool seton);
1125 bool GetEditMode();
1126 wxString GetStringSelection(bool asHTML = false);
1127 wxString GetText(bool asHTML = false);
1128
1129 bool GoBack();
1130 bool GoForward();
1131 bool GoHome();
1132 bool GoSearch();
1133 %name(RefreshPage)bool Refresh(wxIEHtmlRefreshLevel level);
1134 bool Stop();
1135};
1136
1137
1138
1139%pythoncode {
1140wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2 = RegisterActiveXEvent('BeforeNavigate2')
1141wxEVT_COMMAND_MSHTML_NEWWINDOW2 = RegisterActiveXEvent('NewWindow2')
1142wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE = RegisterActiveXEvent('DocumentComplete')
1143wxEVT_COMMAND_MSHTML_PROGRESSCHANGE = RegisterActiveXEvent('ProgressChange')
1144wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE = RegisterActiveXEvent('StatusTextChange')
1145wxEVT_COMMAND_MSHTML_TITLECHANGE = RegisterActiveXEvent('TitleChange')
1146
1147EVT_MSHTML_BEFORENAVIGATE2 = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2, 1)
1148EVT_MSHTML_NEWWINDOW2 = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_NEWWINDOW2, 1)
1149EVT_MSHTML_DOCUMENTCOMPLETE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE, 1)
1150EVT_MSHTML_PROGRESSCHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE, 1)
1151EVT_MSHTML_STATUSTEXTCHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE, 1)
1152EVT_MSHTML_TITLECHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_TITLECHANGE, 1)
1153}
1154
1155#endif
1156
1157//---------------------------------------------------------------------------
1158// Include some extra Python code into the proxy module
1159
1160%pythoncode "_activex_ex.py"
1161
1162//---------------------------------------------------------------------------