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