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