selection.c 12.3 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34
/*
 * Copyright 2006 Jacek Caban for CodeWeavers
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
 */

#include <stdarg.h>

#define COBJMACROS

#include "windef.h"
#include "winbase.h"
#include "winuser.h"
#include "ole2.h"

#include "wine/debug.h"

#include "mshtml_private.h"

WINE_DEFAULT_DEBUG_CHANNEL(mshtml);

typedef struct {
35
    DispatchEx dispex;
36
    IHTMLSelectionObject IHTMLSelectionObject_iface;
37
    IHTMLSelectionObject2 IHTMLSelectionObject2_iface;
38 39 40 41

    LONG ref;

    nsISelection *nsselection;
42
    HTMLDocumentNode *doc;
43 44

    struct list entry;
45 46
} HTMLSelectionObject;

47 48 49 50
static inline HTMLSelectionObject *impl_from_IHTMLSelectionObject(IHTMLSelectionObject *iface)
{
    return CONTAINING_RECORD(iface, HTMLSelectionObject, IHTMLSelectionObject_iface);
}
51 52 53 54

static HRESULT WINAPI HTMLSelectionObject_QueryInterface(IHTMLSelectionObject *iface,
                                                         REFIID riid, void **ppv)
{
55
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
56

57
    TRACE("(%p)->(%s %p)\n", This, debugstr_mshtml_guid(riid), ppv);
58 59

    if(IsEqualGUID(&IID_IUnknown, riid)) {
60
        *ppv = &This->IHTMLSelectionObject_iface;
61
    }else if(IsEqualGUID(&IID_IDispatch, riid)) {
62
        *ppv = &This->IHTMLSelectionObject_iface;
63
    }else if(IsEqualGUID(&IID_IHTMLSelectionObject, riid)) {
64
        *ppv = &This->IHTMLSelectionObject_iface;
65 66
    }else if(IsEqualGUID(&IID_IHTMLSelectionObject2, riid)) {
        *ppv = &This->IHTMLSelectionObject2_iface;
67 68 69 70 71 72
    }else if(dispex_query_interface(&This->dispex, riid, ppv)) {
        return *ppv ? S_OK : E_NOINTERFACE;
    }else {
        *ppv = NULL;
        WARN("(%p)->(%s %p)\n", This, debugstr_guid(riid), ppv);
        return E_NOINTERFACE;
73 74
    }

75 76
    IUnknown_AddRef((IUnknown*)*ppv);
    return S_OK;
77 78 79 80
}

static ULONG WINAPI HTMLSelectionObject_AddRef(IHTMLSelectionObject *iface)
{
81
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
82 83
    LONG ref = InterlockedIncrement(&This->ref);

84
    TRACE("(%p) ref=%d\n", This, ref);
85 86 87 88 89 90

    return ref;
}

static ULONG WINAPI HTMLSelectionObject_Release(IHTMLSelectionObject *iface)
{
91
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
92 93
    LONG ref = InterlockedDecrement(&This->ref);

94
    TRACE("(%p) ref=%d\n", This, ref);
95 96 97 98

    if(!ref) {
        if(This->nsselection)
            nsISelection_Release(This->nsselection);
99 100
        if(This->doc)
            list_remove(&This->entry);
101
        release_dispex(&This->dispex);
102
        heap_free(This);
103 104 105 106 107 108 109
    }

    return ref;
}

static HRESULT WINAPI HTMLSelectionObject_GetTypeInfoCount(IHTMLSelectionObject *iface, UINT *pctinfo)
{
110
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
111 112

    return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
113 114 115 116 117
}

static HRESULT WINAPI HTMLSelectionObject_GetTypeInfo(IHTMLSelectionObject *iface, UINT iTInfo,
                                              LCID lcid, ITypeInfo **ppTInfo)
{
118
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
119 120

    return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
121 122 123 124 125 126
}

static HRESULT WINAPI HTMLSelectionObject_GetIDsOfNames(IHTMLSelectionObject *iface, REFIID riid,
                                                LPOLESTR *rgszNames, UINT cNames,
                                                LCID lcid, DISPID *rgDispId)
{
127
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
128 129 130

    return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames,
            cNames, lcid, rgDispId);
131 132 133 134 135 136
}

static HRESULT WINAPI HTMLSelectionObject_Invoke(IHTMLSelectionObject *iface, DISPID dispIdMember,
                            REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams,
                            VARIANT *pVarResult, EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
137
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
138 139 140 141


    return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid,
            lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
142 143 144 145
}

static HRESULT WINAPI HTMLSelectionObject_createRange(IHTMLSelectionObject *iface, IDispatch **range)
{
146
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
147
    IHTMLTxtRange *range_obj = NULL;
148
    nsIDOMRange *nsrange = NULL;
149
    HRESULT hres;
150 151 152

    TRACE("(%p)->(%p)\n", This, range);

153
    if(This->nsselection) {
154
        LONG nsrange_cnt = 0;
155 156 157
        nsresult nsres;

        nsISelection_GetRangeCount(This->nsselection, &nsrange_cnt);
158 159 160 161 162
        if(!nsrange_cnt) {
            nsIDOMHTMLElement *nsbody = NULL;

            TRACE("nsrange_cnt = 0\n");

163
            if(!This->doc->nsdoc) {
164 165
                WARN("nsdoc is NULL\n");
                return E_UNEXPECTED;
166 167
            }

168
            nsres = nsIDOMHTMLDocument_GetBody(This->doc->nsdoc, &nsbody);
169 170 171 172 173 174 175 176 177 178
            if(NS_FAILED(nsres) || !nsbody) {
                ERR("Could not get body: %08x\n", nsres);
                return E_FAIL;
            }

            nsres = nsISelection_Collapse(This->nsselection, (nsIDOMNode*)nsbody, 0);
            nsIDOMHTMLElement_Release(nsbody);
            if(NS_FAILED(nsres))
                ERR("Collapse failed: %08x\n", nsres);
        }else if(nsrange_cnt > 1) {
179
            FIXME("range_cnt = %d\n", nsrange_cnt);
180
        }
181 182 183 184 185 186

        nsres = nsISelection_GetRangeAt(This->nsselection, 0, &nsrange);
        if(NS_FAILED(nsres))
            ERR("GetRangeAt failed: %08x\n", nsres);
    }

187 188
    hres = HTMLTxtRange_Create(This->doc, nsrange, &range_obj);

189
    if (nsrange) nsIDOMRange_Release(nsrange);
190 191
    *range = (IDispatch*)range_obj;
    return hres;
192 193 194 195
}

static HRESULT WINAPI HTMLSelectionObject_empty(IHTMLSelectionObject *iface)
{
196
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
197 198 199 200 201 202
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

static HRESULT WINAPI HTMLSelectionObject_clear(IHTMLSelectionObject *iface)
{
203
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
204 205 206 207 208 209
    FIXME("(%p)\n", This);
    return E_NOTIMPL;
}

static HRESULT WINAPI HTMLSelectionObject_get_type(IHTMLSelectionObject *iface, BSTR *p)
{
210
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject(iface);
211
    cpp_bool collapsed = TRUE;
212 213 214 215

    TRACE("(%p)->(%p)\n", This, p);

    if(This->nsselection)
216
        nsISelection_GetIsCollapsed(This->nsselection, &collapsed);
217

218
    *p = SysAllocString(collapsed ? L"None" : L"Text"); /* FIXME: control */
219
    TRACE("ret %s\n", debugstr_w(*p));
220
    return S_OK;
221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236
}

static const IHTMLSelectionObjectVtbl HTMLSelectionObjectVtbl = {
    HTMLSelectionObject_QueryInterface,
    HTMLSelectionObject_AddRef,
    HTMLSelectionObject_Release,
    HTMLSelectionObject_GetTypeInfoCount,
    HTMLSelectionObject_GetTypeInfo,
    HTMLSelectionObject_GetIDsOfNames,
    HTMLSelectionObject_Invoke,
    HTMLSelectionObject_createRange,
    HTMLSelectionObject_empty,
    HTMLSelectionObject_clear,
    HTMLSelectionObject_get_type
};

237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306
static inline HTMLSelectionObject *impl_from_IHTMLSelectionObject2(IHTMLSelectionObject2 *iface)
{
    return CONTAINING_RECORD(iface, HTMLSelectionObject, IHTMLSelectionObject2_iface);
}

static HRESULT WINAPI HTMLSelectionObject2_QueryInterface(IHTMLSelectionObject2 *iface, REFIID riid, void **ppv)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);

    return IHTMLSelectionObject_QueryInterface(&This->IHTMLSelectionObject_iface, riid, ppv);
}

static ULONG WINAPI HTMLSelectionObject2_AddRef(IHTMLSelectionObject2 *iface)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);

    return IHTMLSelectionObject_AddRef(&This->IHTMLSelectionObject_iface);
}

static ULONG WINAPI HTMLSelectionObject2_Release(IHTMLSelectionObject2 *iface)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);

    return IHTMLSelectionObject_Release(&This->IHTMLSelectionObject_iface);
}

static HRESULT WINAPI HTMLSelectionObject2_GetTypeInfoCount(IHTMLSelectionObject2 *iface, UINT *pctinfo)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);

    return IDispatchEx_GetTypeInfoCount(&This->dispex.IDispatchEx_iface, pctinfo);
}

static HRESULT WINAPI HTMLSelectionObject2_GetTypeInfo(IHTMLSelectionObject2 *iface, UINT iTInfo,
        LCID lcid, ITypeInfo **ppTInfo)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);

    return IDispatchEx_GetTypeInfo(&This->dispex.IDispatchEx_iface, iTInfo, lcid, ppTInfo);
}

static HRESULT WINAPI HTMLSelectionObject2_GetIDsOfNames(IHTMLSelectionObject2 *iface, REFIID riid,
        LPOLESTR *rgszNames, UINT cNames, LCID lcid, DISPID *rgDispId)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);

    return IDispatchEx_GetIDsOfNames(&This->dispex.IDispatchEx_iface, riid, rgszNames,
            cNames, lcid, rgDispId);
}

static HRESULT WINAPI HTMLSelectionObject2_Invoke(IHTMLSelectionObject2 *iface, DISPID dispIdMember,
        REFIID riid, LCID lcid, WORD wFlags, DISPPARAMS *pDispParams, VARIANT *pVarResult,
        EXCEPINFO *pExcepInfo, UINT *puArgErr)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);

    return IDispatchEx_Invoke(&This->dispex.IDispatchEx_iface, dispIdMember, riid,
            lcid, wFlags, pDispParams, pVarResult, pExcepInfo, puArgErr);
}

static HRESULT WINAPI HTMLSelectionObject2_createRangeCollection(IHTMLSelectionObject2 *iface, IDispatch **rangeCollection)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
    FIXME("(%p)->(%p)\n", This, rangeCollection);
    return E_NOTIMPL;
}

static HRESULT WINAPI HTMLSelectionObject2_get_typeDetail(IHTMLSelectionObject2 *iface, BSTR *p)
{
    HTMLSelectionObject *This = impl_from_IHTMLSelectionObject2(iface);
307 308 309 310

    FIXME("(%p)->(%p) semi-stub\n", This, p);

    /* FIXME: We should try to use ISelectionServicesListener::GetTypeDetail here. */
311
    *p = SysAllocString(L"undefined");
312
    return *p ? S_OK : E_OUTOFMEMORY;
313 314 315 316 317 318 319 320 321 322 323 324 325 326
}

static const IHTMLSelectionObject2Vtbl HTMLSelectionObject2Vtbl = {
    HTMLSelectionObject2_QueryInterface,
    HTMLSelectionObject2_AddRef,
    HTMLSelectionObject2_Release,
    HTMLSelectionObject2_GetTypeInfoCount,
    HTMLSelectionObject2_GetTypeInfo,
    HTMLSelectionObject2_GetIDsOfNames,
    HTMLSelectionObject2_Invoke,
    HTMLSelectionObject2_createRangeCollection,
    HTMLSelectionObject2_get_typeDetail
};

327 328
static const tid_t HTMLSelectionObject_iface_tids[] = {
    IHTMLSelectionObject_tid,
329
    IHTMLSelectionObject2_tid,
330 331 332 333
    0
};
static dispex_static_data_t HTMLSelectionObject_dispex = {
    NULL,
334
    IHTMLSelectionObject_tid, /* FIXME: We have a test for that, but it doesn't expose IHTMLSelectionObject2 iface. */
335 336 337
    HTMLSelectionObject_iface_tids
};

338
HRESULT HTMLSelectionObject_Create(HTMLDocumentNode *doc, nsISelection *nsselection, IHTMLSelectionObject **ret)
339
{
340
    HTMLSelectionObject *selection;
341

342 343 344
    selection = heap_alloc(sizeof(HTMLSelectionObject));
    if(!selection)
        return E_OUTOFMEMORY;
345

346 347
    init_dispatch(&selection->dispex, (IUnknown*)&selection->IHTMLSelectionObject_iface,
                  &HTMLSelectionObject_dispex, dispex_compat_mode(&doc->node.event_target.dispex));
348

349
    selection->IHTMLSelectionObject_iface.lpVtbl = &HTMLSelectionObjectVtbl;
350
    selection->IHTMLSelectionObject2_iface.lpVtbl = &HTMLSelectionObject2Vtbl;
351 352
    selection->ref = 1;
    selection->nsselection = nsselection; /* We shouldn't call AddRef here */
353

354 355 356
    selection->doc = doc;
    list_add_head(&doc->selection_list, &selection->entry);

357
    *ret = &selection->IHTMLSelectionObject_iface;
358
    return S_OK;
359
}
360

361
void detach_selection(HTMLDocumentNode *This)
362
{
363
    HTMLSelectionObject *iter, *next;
364

365
    LIST_FOR_EACH_ENTRY_SAFE(iter, next, &This->selection_list, HTMLSelectionObject, entry) {
366
        iter->doc = NULL;
367
        list_remove(&iter->entry);
368 369
    }
}