mshtml: Added more edit mode tests.
[wine] / dlls / mshtml / conpoint.c
1 /*
2  * Copyright 2006 Jacek Caban for CodeWeavers
3  *
4  * This library is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU Lesser General Public
6  * License as published by the Free Software Foundation; either
7  * version 2.1 of the License, or (at your option) any later version.
8  *
9  * This library is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * Lesser General Public License for more details.
13  *
14  * You should have received a copy of the GNU Lesser General Public
15  * License along with this library; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
17  */
18
19 #include "config.h"
20
21 #include <stdarg.h>
22 #include <stdio.h>
23
24 #define COBJMACROS
25
26 #include "windef.h"
27 #include "winbase.h"
28 #include "winuser.h"
29 #include "ole2.h"
30
31 #include "wine/debug.h"
32
33 #include "mshtml_private.h"
34
35 WINE_DEFAULT_DEBUG_CHANNEL(mshtml);
36
37 #define CONPOINT(x) ((IConnectionPoint*) &(x)->lpConnectionPointVtbl);
38
39 struct ConnectionPoint {
40     const IConnectionPointVtbl *lpConnectionPointVtbl;
41
42     HTMLDocument *doc;
43
44     union {
45         IUnknown *unk;
46         IDispatch *disp;
47         IPropertyNotifySink *propnotif;
48     } *sinks;
49     DWORD sinks_size;
50
51     IID iid;
52 };
53
54 void call_property_onchanged(ConnectionPoint *This, DISPID dispid)
55 {
56     DWORD i;
57
58     for(i=0; i<This->sinks_size; i++) {
59         if(This->sinks[i].propnotif)
60             IPropertyNotifySink_OnChanged(This->sinks[i].propnotif, dispid);
61     }
62 }
63
64 #define CONPOINT_THIS(iface) DEFINE_THIS(ConnectionPoint, ConnectionPoint, iface)
65
66 static HRESULT WINAPI ConnectionPoint_QueryInterface(IConnectionPoint *iface,
67                                                      REFIID riid, LPVOID *ppv)
68 {
69     ConnectionPoint *This = CONPOINT_THIS(iface);
70
71     *ppv = NULL;
72
73     if(IsEqualGUID(&IID_IUnknown, riid)) {
74         TRACE("(%p)->(IID_IUnknown %p)\n", This, ppv);
75         *ppv = CONPOINT(This);
76     }else if(IsEqualGUID(&IID_IConnectionPoint, riid)) {
77         TRACE("(%p)->(IID_IConnectionPoint %p)\n", This, ppv);
78         *ppv = CONPOINT(This);
79     }
80
81     if(*ppv) {
82         IUnknown_AddRef((IUnknown*)*ppv);
83         return S_OK;
84     }
85
86     WARN("Unsupported interface %s\n", debugstr_guid(riid));
87     return E_NOINTERFACE;
88 }
89
90 static ULONG WINAPI ConnectionPoint_AddRef(IConnectionPoint *iface)
91 {
92     ConnectionPoint *This = CONPOINT_THIS(iface);
93     return IHTMLDocument2_AddRef(HTMLDOC(This->doc));
94 }
95
96 static ULONG WINAPI ConnectionPoint_Release(IConnectionPoint *iface)
97 {
98     ConnectionPoint *This = CONPOINT_THIS(iface);
99     return IHTMLDocument2_Release(HTMLDOC(This->doc));
100 }
101
102 static HRESULT WINAPI ConnectionPoint_GetConnectionInterface(IConnectionPoint *iface, IID *pIID)
103 {
104     ConnectionPoint *This = CONPOINT_THIS(iface);
105
106     TRACE("(%p)->(%p)\n", This, pIID);
107
108     if(!pIID)
109         return E_POINTER;
110
111     memcpy(pIID, &This->iid, sizeof(IID));
112     return S_OK;
113 }
114
115 static HRESULT WINAPI ConnectionPoint_GetConnectionPointContainer(IConnectionPoint *iface,
116         IConnectionPointContainer **ppCPC)
117 {
118     ConnectionPoint *This = CONPOINT_THIS(iface);
119
120     TRACE("(%p)->(%p)\n", This, ppCPC);
121
122     if(!ppCPC)
123         return E_POINTER;
124
125     *ppCPC = CONPTCONT(This->doc);
126     IConnectionPointContainer_AddRef(*ppCPC);
127     return S_OK;
128 }
129
130 static HRESULT WINAPI ConnectionPoint_Advise(IConnectionPoint *iface, IUnknown *pUnkSink,
131                                              DWORD *pdwCookie)
132 {
133     ConnectionPoint *This = CONPOINT_THIS(iface);
134     IUnknown *sink;
135     DWORD i;
136     HRESULT hres;
137
138     TRACE("(%p)->(%p %p)\n", This, pUnkSink, pdwCookie);
139
140     hres = IUnknown_QueryInterface(pUnkSink, &This->iid, (void**)&sink);
141     if(FAILED(hres) && !IsEqualGUID(&IID_IPropertyNotifySink, &This->iid))
142         hres = IUnknown_QueryInterface(pUnkSink, &IID_IDispatch, (void**)&sink);
143     if(FAILED(hres))
144         return CONNECT_E_CANNOTCONNECT;
145
146     if(This->sinks) {
147         for(i=0; i<This->sinks_size; i++) {
148             if(!This->sinks[i].unk)
149                 break;
150         }
151
152         if(i == This->sinks_size)
153             This->sinks = mshtml_realloc(This->sinks,(++This->sinks_size)*sizeof(*This->sinks));
154     }else {
155         This->sinks = mshtml_alloc(sizeof(*This->sinks));
156         This->sinks_size = 1;
157         i = 0;
158     }
159
160     This->sinks[i].unk = sink;
161     *pdwCookie = i+1;
162
163     return S_OK;
164 }
165
166 static HRESULT WINAPI ConnectionPoint_Unadvise(IConnectionPoint *iface, DWORD dwCookie)
167 {
168     ConnectionPoint *This = CONPOINT_THIS(iface);
169     TRACE("(%p)->(%d)\n", This, dwCookie);
170
171     if(!dwCookie || dwCookie > This->sinks_size || !This->sinks[dwCookie-1].unk)
172         return CONNECT_E_NOCONNECTION;
173
174     IUnknown_Release(This->sinks[dwCookie-1].unk);
175     This->sinks[dwCookie-1].unk = NULL;
176
177     return S_OK;
178 }
179
180 static HRESULT WINAPI ConnectionPoint_EnumConnections(IConnectionPoint *iface,
181                                                       IEnumConnections **ppEnum)
182 {
183     ConnectionPoint *This = CONPOINT_THIS(iface);
184     FIXME("(%p)->(%p)\n", This, ppEnum);
185     return E_NOTIMPL;
186 }
187
188 #undef CONPOINT_THIS
189
190 static const IConnectionPointVtbl ConnectionPointVtbl =
191 {
192     ConnectionPoint_QueryInterface,
193     ConnectionPoint_AddRef,
194     ConnectionPoint_Release,
195     ConnectionPoint_GetConnectionInterface,
196     ConnectionPoint_GetConnectionPointContainer,
197     ConnectionPoint_Advise,
198     ConnectionPoint_Unadvise,
199     ConnectionPoint_EnumConnections
200 };
201
202 static void ConnectionPoint_Create(HTMLDocument *doc, REFIID riid, ConnectionPoint **cp)
203 {
204     ConnectionPoint *ret = mshtml_alloc(sizeof(ConnectionPoint));
205
206     ret->lpConnectionPointVtbl = &ConnectionPointVtbl;
207     ret->doc = doc;
208     ret->sinks = NULL;
209     ret->sinks_size = 0;
210     memcpy(&ret->iid, riid, sizeof(IID));
211
212     *cp = ret;
213 }
214
215 static void ConnectionPoint_Destroy(ConnectionPoint *This)
216 {
217     int i;
218
219     for(i=0; i<This->sinks_size; i++) {
220         if(This->sinks[i].unk)
221             IUnknown_Release(This->sinks[i].unk);
222     }
223
224     mshtml_free(This->sinks);
225     mshtml_free(This);
226 }
227
228 #define CONPTCONT_THIS(iface) DEFINE_THIS(HTMLDocument, ConnectionPointContainer, iface)
229
230 static HRESULT WINAPI ConnectionPointContainer_QueryInterface(IConnectionPointContainer *iface,
231                                                               REFIID riid, void **ppv)
232 {
233     HTMLDocument *This = CONPTCONT_THIS(iface);
234     return IHTMLDocument2_QueryInterface(HTMLDOC(This), riid, ppv);
235 }
236
237 static ULONG WINAPI ConnectionPointContainer_AddRef(IConnectionPointContainer *iface)
238 {
239     HTMLDocument *This = CONPTCONT_THIS(iface);
240     return IHTMLDocument2_AddRef(HTMLDOC(This));
241 }
242
243 static ULONG WINAPI ConnectionPointContainer_Release(IConnectionPointContainer *iface)
244 {
245     HTMLDocument *This = CONPTCONT_THIS(iface);
246     return IHTMLDocument2_Release(HTMLDOC(This));
247 }
248
249 static HRESULT WINAPI ConnectionPointContainer_EnumConnectionPoints(IConnectionPointContainer *iface,
250         IEnumConnectionPoints **ppEnum)
251 {
252     HTMLDocument *This = CONPTCONT_THIS(iface);
253     FIXME("(%p)->(%p)\n", This, ppEnum);
254     return E_NOTIMPL;
255 }
256
257 static HRESULT WINAPI ConnectionPointContainer_FindConnectionPoint(IConnectionPointContainer *iface,
258         REFIID riid, IConnectionPoint **ppCP)
259 {
260     HTMLDocument *This = CONPTCONT_THIS(iface);
261
262     *ppCP = NULL;
263
264     if(IsEqualGUID(&DIID_HTMLDocumentEvents, riid)) {
265         TRACE("(%p)->(DIID_HTMLDocumentEvents %p)\n", This, ppCP);
266         *ppCP = CONPOINT(This->cp_htmldocevents);
267     }else if(IsEqualGUID(&DIID_HTMLDocumentEvents2, riid)) {
268         TRACE("(%p)->(DIID_HTMLDocumentEvents2 %p)\n", This, ppCP);
269         *ppCP = CONPOINT(This->cp_htmldocevents2);
270     }else if(IsEqualGUID(&IID_IPropertyNotifySink, riid)) {
271         TRACE("(%p)->(IID_IPropertyNotifySink %p)\n", This, ppCP);
272         *ppCP = CONPOINT(This->cp_propnotif);
273     }
274
275     if(*ppCP) {
276         IConnectionPoint_AddRef(*ppCP);
277         return S_OK;
278     }
279
280     FIXME("(%p)->(%s %p) unsupported riid\n", This, debugstr_guid(riid), ppCP);
281     return CONNECT_E_NOCONNECTION;
282 }
283
284 static const IConnectionPointContainerVtbl ConnectionPointContainerVtbl = {
285     ConnectionPointContainer_QueryInterface,
286     ConnectionPointContainer_AddRef,
287     ConnectionPointContainer_Release,
288     ConnectionPointContainer_EnumConnectionPoints,
289     ConnectionPointContainer_FindConnectionPoint
290 };
291
292 #undef CONPTCONT_THIS
293
294 void HTMLDocument_ConnectionPoints_Init(HTMLDocument *This)
295 {
296     This->lpConnectionPointContainerVtbl = &ConnectionPointContainerVtbl;
297
298     ConnectionPoint_Create(This, &IID_IPropertyNotifySink, &This->cp_propnotif);
299     ConnectionPoint_Create(This, &DIID_HTMLDocumentEvents, &This->cp_htmldocevents);
300     ConnectionPoint_Create(This, &DIID_HTMLDocumentEvents2, &This->cp_htmldocevents2);
301 }
302
303 void HTMLDocument_ConnectionPoints_Destroy(HTMLDocument *This)
304 {
305     ConnectionPoint_Destroy(This->cp_propnotif);
306     ConnectionPoint_Destroy(This->cp_htmldocevents);
307     ConnectionPoint_Destroy(This->cp_htmldocevents2);
308 }