]> git.saurik.com Git - wxWidgets.git/blob - wxPython/contrib/activex/activex.i
426115880a75f38f1a9dfff2bf3dfe7dc24f748d
[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 // web browser setup
835 m_webBrowser->put_MenuBar(VARIANT_FALSE);
836 m_webBrowser->put_AddressBar(VARIANT_FALSE);
837 m_webBrowser->put_StatusBar(VARIANT_FALSE);
838 m_webBrowser->put_ToolBar(VARIANT_FALSE);
839
840 m_webBrowser->put_RegisterAsBrowser(VARIANT_TRUE);
841 m_webBrowser->put_RegisterAsDropTarget(VARIANT_TRUE);
842
843 m_webBrowser->Navigate( L"about:blank", NULL, NULL, NULL, NULL );
844 }
845
846
847 void SetCharset(const wxString& charset)
848 {
849 HRESULT hret;
850
851 // HTML Document ?
852 IDispatch *pDisp = NULL;
853 hret = m_webBrowser->get_Document(&pDisp);
854 wxAutoOleInterface<IDispatch> disp(pDisp);
855
856 if (disp.Ok())
857 {
858 wxAutoOleInterface<IHTMLDocument2> doc(IID_IHTMLDocument2, disp);
859 if (doc.Ok())
860 doc->put_charset((BSTR) (const wchar_t *) charset.wc_str(wxConvUTF8));
861 //doc->put_charset((BSTR) wxConvUTF8.cMB2WC(charset).data());
862 }
863 }
864
865
866 bool LoadString(const wxString& html)
867 {
868 char *data = NULL;
869 size_t len = html.length();
870 len *= sizeof(wxChar);
871 data = (char *) malloc(len);
872 memcpy(data, html.c_str(), len);
873 return LoadStream(new wxOwnedMemInputStream(data, len));
874 }
875
876
877 bool LoadStream(IStreamAdaptorBase *pstrm)
878 {
879 // need to prepend this as poxy MSHTML will not recognise a HTML comment
880 // as starting a html document and treats it as plain text
881 // Does nayone know how to force it to html mode ?
882 pstrm->prepend = "<html>";
883
884 // strip leading whitespace as it can confuse MSHTML
885 wxAutoOleInterface<IStream> strm(pstrm);
886
887 // Document Interface
888 IDispatch *pDisp = NULL;
889 HRESULT hret = m_webBrowser->get_Document(&pDisp);
890 if (! pDisp)
891 return false;
892 wxAutoOleInterface<IDispatch> disp(pDisp);
893
894
895 // get IPersistStreamInit
896 wxAutoOleInterface<IPersistStreamInit>
897 pPersistStreamInit(IID_IPersistStreamInit, disp);
898
899 if (pPersistStreamInit.Ok())
900 {
901 HRESULT hr = pPersistStreamInit->InitNew();
902 if (SUCCEEDED(hr))
903 hr = pPersistStreamInit->Load(strm);
904
905 return SUCCEEDED(hr);
906 }
907 else
908 return false;
909 }
910
911 bool LoadStream(wxInputStream *is)
912 {
913 // wrap reference around stream
914 IwxStreamAdaptor *pstrm = new IwxStreamAdaptor(is);
915 pstrm->AddRef();
916
917 return LoadStream(pstrm);
918 }
919
920
921 wxString GetStringSelection(bool asHTML)
922 {
923 wxAutoOleInterface<IHTMLTxtRange> tr(wxieGetSelRange(m_oleObject));
924 if (! tr)
925 return wxEmptyString;
926
927 BSTR text = NULL;
928 HRESULT hr = E_FAIL;
929
930 if (asHTML)
931 hr = tr->get_htmlText(&text);
932 else
933 hr = tr->get_text(&text);
934 if (hr != S_OK)
935 return wxEmptyString;
936
937 wxString s = text;
938 SysFreeString(text);
939
940 return s;
941 };
942
943 wxString GetText(bool asHTML)
944 {
945 if (! m_webBrowser.Ok())
946 return wxEmptyString;
947
948 // get document dispatch interface
949 IDispatch *iDisp = NULL;
950 HRESULT hr = m_webBrowser->get_Document(&iDisp);
951 if (hr != S_OK)
952 return wxEmptyString;
953
954 // Query for Document Interface
955 wxAutoOleInterface<IHTMLDocument2> hd(IID_IHTMLDocument2, iDisp);
956 iDisp->Release();
957
958 if (! hd.Ok())
959 return wxEmptyString;
960
961 // get body element
962 IHTMLElement *_body = NULL;
963 hd->get_body(&_body);
964 if (! _body)
965 return wxEmptyString;
966 wxAutoOleInterface<IHTMLElement> body(_body);
967
968 // get inner text
969 BSTR text = NULL;
970 hr = E_FAIL;
971
972 if (asHTML)
973 hr = body->get_innerHTML(&text);
974 else
975 hr = body->get_innerText(&text);
976 if (hr != S_OK)
977 return wxEmptyString;
978
979 wxString s = text;
980 SysFreeString(text);
981
982 return s;
983 }
984
985
986 // void wxIEHtmlWin::SetEditMode(bool seton)
987 // {
988 // m_bAmbientUserMode = ! seton;
989 // AmbientPropertyChanged(DISPID_AMBIENT_USERMODE);
990 // };
991
992 // bool wxIEHtmlWin::GetEditMode()
993 // {
994 // return ! m_bAmbientUserMode;
995 // };
996 };
997 %}
998
999
1000 // we'll document it in the derived Python class
1001 %feature("noautodoc") wxIEHtmlWindowBase;
1002 %feature("noautodoc") wxIEHtmlWindowBase::SetCharset;
1003 %feature("noautodoc") wxIEHtmlWindowBase::LoadString;
1004 %feature("noautodoc") wxIEHtmlWindowBase::LoadStream;
1005 %feature("noautodoc") wxIEHtmlWindowBase::GetStringSelection;
1006 %feature("noautodoc") wxIEHtmlWindowBase::GetText;
1007
1008
1009 class wxIEHtmlWindowBase : public wxActiveXWindow {
1010 public:
1011
1012 wxIEHtmlWindowBase ( wxWindow* parent, const CLSID& clsId, wxWindowID id = -1,
1013 const wxPoint& pos = wxDefaultPosition,
1014 const wxSize& size = wxDefaultSize,
1015 long style = 0,
1016 const wxString& name = wxPyPanelNameStr);
1017
1018 void SetCharset(const wxString& charset);
1019 bool LoadString(const wxString& html);
1020 bool LoadStream(wxInputStream *is);
1021 wxString GetStringSelection(bool asHTML);
1022 wxString GetText(bool asHTML);
1023 };
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035 #if 0
1036 enum wxIEHtmlRefreshLevel
1037 {
1038 wxIEHTML_REFRESH_NORMAL = 0,
1039 wxIEHTML_REFRESH_IFEXPIRED = 1,
1040 wxIEHTML_REFRESH_CONTINUE = 2,
1041 wxIEHTML_REFRESH_COMPLETELY = 3
1042 };
1043
1044 DocStr(wxIEHtmlWin,
1045 "");
1046 class wxIEHtmlWin : public wxWindow
1047 {
1048 public:
1049 %pythonAppend wxIEHtmlWin "self._setOORInfo(self)"
1050
1051 wxIEHtmlWin(wxWindow * parent, wxWindowID id = -1,
1052 const wxPoint& pos = wxDefaultPosition,
1053 const wxSize& size = wxDefaultSize,
1054 long style = 0,
1055 const wxString& name = wxPyPanelNameStr);
1056
1057 void LoadUrl(const wxString& url);
1058 bool LoadString(wxString html);
1059 bool LoadStream(wxInputStream *is);
1060
1061 %pythoncode { Navigate = LoadUrl }
1062
1063 void SetCharset(wxString charset);
1064 void SetEditMode(bool seton);
1065 bool GetEditMode();
1066 wxString GetStringSelection(bool asHTML = false);
1067 wxString GetText(bool asHTML = false);
1068
1069 bool GoBack();
1070 bool GoForward();
1071 bool GoHome();
1072 bool GoSearch();
1073 %name(RefreshPage)bool Refresh(wxIEHtmlRefreshLevel level);
1074 bool Stop();
1075 };
1076
1077
1078
1079 %pythoncode {
1080 wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2 = RegisterActiveXEvent('BeforeNavigate2')
1081 wxEVT_COMMAND_MSHTML_NEWWINDOW2 = RegisterActiveXEvent('NewWindow2')
1082 wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE = RegisterActiveXEvent('DocumentComplete')
1083 wxEVT_COMMAND_MSHTML_PROGRESSCHANGE = RegisterActiveXEvent('ProgressChange')
1084 wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE = RegisterActiveXEvent('StatusTextChange')
1085 wxEVT_COMMAND_MSHTML_TITLECHANGE = RegisterActiveXEvent('TitleChange')
1086
1087 EVT_MSHTML_BEFORENAVIGATE2 = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_BEFORENAVIGATE2, 1)
1088 EVT_MSHTML_NEWWINDOW2 = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_NEWWINDOW2, 1)
1089 EVT_MSHTML_DOCUMENTCOMPLETE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_DOCUMENTCOMPLETE, 1)
1090 EVT_MSHTML_PROGRESSCHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_PROGRESSCHANGE, 1)
1091 EVT_MSHTML_STATUSTEXTCHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_STATUSTEXTCHANGE, 1)
1092 EVT_MSHTML_TITLECHANGE = wx.PyEventBinder(wxEVT_COMMAND_MSHTML_TITLECHANGE, 1)
1093 }
1094
1095 #endif
1096
1097 //---------------------------------------------------------------------------
1098 // Include some extra Python code into the proxy module
1099
1100 %pythoncode "_activex_ex.py"
1101
1102 //---------------------------------------------------------------------------