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