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