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