~ubuntu-branches/ubuntu/precise/kompozer/precise

« back to all changes in this revision

Viewing changes to mozilla/rdf/base/src/nsRDFContainer.cpp

  • Committer: Bazaar Package Importer
  • Author(s): Anthony Yarusso
  • Date: 2007-08-27 01:11:03 UTC
  • Revision ID: james.westby@ubuntu.com-20070827011103-2jgf4s6532gqu2ka
Tags: upstream-0.7.10
ImportĀ upstreamĀ versionĀ 0.7.10

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
 
2
/* ***** BEGIN LICENSE BLOCK *****
 
3
 * Version: NPL 1.1/GPL 2.0/LGPL 2.1
 
4
 *
 
5
 * The contents of this file are subject to the Netscape Public License
 
6
 * Version 1.1 (the "License"); you may not use this file except in
 
7
 * compliance with the License. You may obtain a copy of the License at
 
8
 * http://www.mozilla.org/NPL/
 
9
 *
 
10
 * Software distributed under the License is distributed on an "AS IS" basis,
 
11
 * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License
 
12
 * for the specific language governing rights and limitations under the
 
13
 * License.
 
14
 *
 
15
 * The Original Code is Mozilla Communicator client code.
 
16
 *
 
17
 * The Initial Developer of the Original Code is 
 
18
 * Netscape Communications Corporation.
 
19
 * Portions created by the Initial Developer are Copyright (C) 1998
 
20
 * the Initial Developer. All Rights Reserved.
 
21
 *
 
22
 * Contributor(s):
 
23
 *   Pierre Phaneuf <pp@ludusdesign.com>
 
24
 *
 
25
 * Alternatively, the contents of this file may be used under the terms of
 
26
 * either the GNU General Public License Version 2 or later (the "GPL"), or 
 
27
 * the GNU Lesser General Public License Version 2.1 or later (the "LGPL"),
 
28
 * in which case the provisions of the GPL or the LGPL are applicable instead
 
29
 * of those above. If you wish to allow use of your version of this file only
 
30
 * under the terms of either the GPL or the LGPL, and not to allow others to
 
31
 * use your version of this file under the terms of the NPL, indicate your
 
32
 * decision by deleting the provisions above and replace them with the notice
 
33
 * and other provisions required by the GPL or the LGPL. If you do not delete
 
34
 * the provisions above, a recipient may use your version of this file under
 
35
 * the terms of any one of the NPL, the GPL or the LGPL.
 
36
 *
 
37
 * ***** END LICENSE BLOCK ***** */
 
38
 
 
39
/*
 
40
 
 
41
  Implementation for the RDF container.
 
42
 
 
43
  Notes
 
44
  -----
 
45
 
 
46
  1. RDF containers are one-indexed. This means that a lot of the loops
 
47
     that you'd normally think you'd write like this:
 
48
 
 
49
       for (i = 0; i < count; ++i) {}
 
50
 
 
51
     You've gotta write like this:
 
52
 
 
53
       for (i = 1; i <= count; ++i) {}
 
54
 
 
55
     "Sure, right, yeah, of course.", you say. Well maybe I'm just
 
56
     thick, but it's easy to slip up.
 
57
 
 
58
  2. The RDF:nextVal property on the container is an
 
59
     implementation-level hack that is used to quickly compute the
 
60
     next value for appending to the container. It will no doubt
 
61
     become royally screwed up in the case of aggregation.
 
62
 
 
63
  3. The RDF:nextVal property is also used to retrieve the count of
 
64
     elements in the container.
 
65
 
 
66
 */
 
67
 
 
68
 
 
69
#include "nsCOMPtr.h"
 
70
#include "nsIRDFContainer.h"
 
71
#include "nsIRDFContainerUtils.h"
 
72
#include "nsIRDFInMemoryDataSource.h"
 
73
#include "nsIRDFPropagatableDataSource.h"
 
74
#include "nsIRDFService.h"
 
75
#include "nsIServiceManager.h"
 
76
#include "nsRDFCID.h"
 
77
#include "nsString.h"
 
78
#include "nsXPIDLString.h"
 
79
#include "rdf.h"
 
80
 
 
81
static NS_DEFINE_CID(kRDFServiceCID, NS_RDFSERVICE_CID);
 
82
static NS_DEFINE_CID(kRDFContainerUtilsCID, NS_RDFCONTAINERUTILS_CID);
 
83
static const char kRDFNameSpaceURI[] = RDF_NAMESPACE_URI;
 
84
 
 
85
#define RDF_SEQ_LIST_LIMIT   8
 
86
 
 
87
class RDFContainerImpl : public nsIRDFContainer
 
88
{
 
89
public:
 
90
 
 
91
    // nsISupports interface
 
92
    NS_DECL_ISUPPORTS
 
93
 
 
94
    // nsIRDFContainer interface
 
95
    NS_DECL_NSIRDFCONTAINER
 
96
 
 
97
private:
 
98
    friend nsresult NS_NewRDFContainer(nsIRDFContainer** aResult);
 
99
 
 
100
    RDFContainerImpl();
 
101
    virtual ~RDFContainerImpl();
 
102
 
 
103
    nsresult Init();
 
104
 
 
105
    nsresult Renumber(PRInt32 aStartIndex, PRInt32 aIncrement);
 
106
    nsresult SetNextValue(PRInt32 aIndex);
 
107
    nsresult GetNextValue(nsIRDFResource** aResult);
 
108
    
 
109
    nsIRDFDataSource* mDataSource;
 
110
    nsIRDFResource*   mContainer;
 
111
 
 
112
    // pseudo constants
 
113
    static PRInt32 gRefCnt;
 
114
    static nsIRDFService*        gRDFService;
 
115
    static nsIRDFContainerUtils* gRDFContainerUtils;
 
116
    static nsIRDFResource*       kRDF_nextVal;
 
117
};
 
118
 
 
119
 
 
120
PRInt32               RDFContainerImpl::gRefCnt = 0;
 
121
nsIRDFService*        RDFContainerImpl::gRDFService;
 
122
nsIRDFContainerUtils* RDFContainerImpl::gRDFContainerUtils;
 
123
nsIRDFResource*       RDFContainerImpl::kRDF_nextVal;
 
124
 
 
125
////////////////////////////////////////////////////////////////////////
 
126
// nsISupports interface
 
127
 
 
128
NS_IMPL_ISUPPORTS1(RDFContainerImpl, nsIRDFContainer)
 
129
 
 
130
 
 
131
 
 
132
////////////////////////////////////////////////////////////////////////
 
133
// nsIRDFContainer interface
 
134
 
 
135
NS_IMETHODIMP
 
136
RDFContainerImpl::GetDataSource(nsIRDFDataSource** _retval)
 
137
{
 
138
    *_retval = mDataSource;
 
139
    NS_IF_ADDREF(*_retval);
 
140
    return NS_OK;
 
141
}
 
142
 
 
143
 
 
144
NS_IMETHODIMP
 
145
RDFContainerImpl::GetResource(nsIRDFResource** _retval)
 
146
{
 
147
    *_retval = mContainer;
 
148
    NS_IF_ADDREF(*_retval);
 
149
    return NS_OK;
 
150
}
 
151
 
 
152
 
 
153
NS_IMETHODIMP
 
154
RDFContainerImpl::Init(nsIRDFDataSource *aDataSource, nsIRDFResource *aContainer)
 
155
{
 
156
    NS_PRECONDITION(aDataSource != nsnull, "null ptr");
 
157
    if (! aDataSource)
 
158
        return NS_ERROR_NULL_POINTER;
 
159
 
 
160
    NS_PRECONDITION(aContainer != nsnull, "null ptr");
 
161
    if (! aContainer)
 
162
        return NS_ERROR_NULL_POINTER;
 
163
 
 
164
    nsresult rv;
 
165
    PRBool isContainer;
 
166
    rv = gRDFContainerUtils->IsContainer(aDataSource, aContainer, &isContainer);
 
167
    if (NS_FAILED(rv)) return rv;
 
168
 
 
169
    // ``throw'' if we can't create a container on the specified
 
170
    // datasource/resource combination.
 
171
    if (! isContainer)
 
172
        return NS_ERROR_FAILURE;
 
173
 
 
174
    NS_IF_RELEASE(mDataSource);
 
175
    mDataSource = aDataSource;
 
176
    NS_ADDREF(mDataSource);
 
177
 
 
178
    NS_IF_RELEASE(mContainer);
 
179
    mContainer = aContainer;
 
180
    NS_ADDREF(mContainer);
 
181
 
 
182
    return NS_OK;
 
183
}
 
184
 
 
185
 
 
186
NS_IMETHODIMP
 
187
RDFContainerImpl::GetCount(PRInt32 *aCount)
 
188
{
 
189
    if (!mDataSource || !mContainer)
 
190
        return NS_ERROR_NOT_INITIALIZED;
 
191
 
 
192
    nsresult rv;
 
193
 
 
194
    // Get the next value, which hangs off of the bag via the
 
195
    // RDF:nextVal property. This is the _next value_ that will get
 
196
    // assigned in a one-indexed array. So, it's actually _one more_
 
197
    // than the actual count of elements in the container.
 
198
    //
 
199
    // XXX To handle aggregation, this should probably be a
 
200
    // GetTargets() that enumerates all of the values and picks the
 
201
    // largest one.
 
202
    nsCOMPtr<nsIRDFNode> nextValNode;
 
203
    rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, PR_TRUE, getter_AddRefs(nextValNode));
 
204
    if (NS_FAILED(rv)) return rv;
 
205
 
 
206
    if (rv == NS_RDF_NO_VALUE)
 
207
        return NS_ERROR_UNEXPECTED;
 
208
 
 
209
    nsCOMPtr<nsIRDFLiteral> nextValLiteral;
 
210
    rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
 
211
    if (NS_FAILED(rv)) return rv;
 
212
 
 
213
    const PRUnichar *s;
 
214
    rv = nextValLiteral->GetValueConst( &s );
 
215
    if (NS_FAILED(rv)) return rv;
 
216
 
 
217
    nsAutoString nextValStr(s);
 
218
 
 
219
    PRInt32 nextVal;
 
220
    PRInt32 err;
 
221
    nextVal = nextValStr.ToInteger(&err);
 
222
    if (NS_FAILED(err))
 
223
        return NS_ERROR_UNEXPECTED;
 
224
 
 
225
    *aCount = nextVal - 1;
 
226
    return NS_OK;
 
227
}
 
228
 
 
229
 
 
230
NS_IMETHODIMP
 
231
RDFContainerImpl::GetElements(nsISimpleEnumerator **_retval)
 
232
{
 
233
    if (!mDataSource || !mContainer)
 
234
        return NS_ERROR_NOT_INITIALIZED;
 
235
 
 
236
    return NS_NewContainerEnumerator(mDataSource, mContainer, _retval);
 
237
}
 
238
 
 
239
 
 
240
NS_IMETHODIMP
 
241
RDFContainerImpl::AppendElement(nsIRDFNode *aElement)
 
242
{
 
243
    if (!mDataSource || !mContainer)
 
244
        return NS_ERROR_NOT_INITIALIZED;
 
245
 
 
246
    NS_PRECONDITION(aElement != nsnull, "null ptr");
 
247
    if (! aElement)
 
248
        return NS_ERROR_NULL_POINTER;
 
249
 
 
250
    nsresult rv;
 
251
 
 
252
    nsCOMPtr<nsIRDFResource> nextVal;
 
253
    rv = GetNextValue(getter_AddRefs(nextVal));
 
254
    if (NS_FAILED(rv)) return rv;
 
255
 
 
256
    rv = mDataSource->Assert(mContainer, nextVal, aElement, PR_TRUE);
 
257
    if (NS_FAILED(rv)) return rv;
 
258
 
 
259
    return NS_OK;
 
260
}
 
261
 
 
262
 
 
263
NS_IMETHODIMP
 
264
RDFContainerImpl::RemoveElement(nsIRDFNode *aElement, PRBool aRenumber)
 
265
{
 
266
    if (!mDataSource || !mContainer)
 
267
        return NS_ERROR_NOT_INITIALIZED;
 
268
 
 
269
    NS_PRECONDITION(aElement != nsnull, "null ptr");
 
270
    if (! aElement)
 
271
        return NS_ERROR_NULL_POINTER;
 
272
 
 
273
    nsresult rv;
 
274
 
 
275
    PRInt32 idx;
 
276
    rv = IndexOf(aElement, &idx);
 
277
    if (NS_FAILED(rv)) return rv;
 
278
 
 
279
    if (idx < 0)
 
280
        return NS_OK;
 
281
 
 
282
    // Remove the element.
 
283
    nsCOMPtr<nsIRDFResource> ordinal;
 
284
    rv = gRDFContainerUtils->IndexToOrdinalResource(idx,
 
285
                                                    getter_AddRefs(ordinal));
 
286
    if (NS_FAILED(rv)) return rv;
 
287
 
 
288
    rv = mDataSource->Unassert(mContainer, ordinal, aElement);
 
289
    if (NS_FAILED(rv)) return rv;
 
290
 
 
291
    if (aRenumber) {
 
292
        // Now slide the rest of the collection backwards to fill in
 
293
        // the gap. This will have the side effect of completely
 
294
        // renumber the container from index to the end.
 
295
        rv = Renumber(idx + 1, -1);
 
296
        if (NS_FAILED(rv)) return rv;
 
297
    }
 
298
 
 
299
    return NS_OK;
 
300
}
 
301
 
 
302
 
 
303
NS_IMETHODIMP
 
304
RDFContainerImpl::InsertElementAt(nsIRDFNode *aElement, PRInt32 aIndex, PRBool aRenumber)
 
305
{
 
306
    if (!mDataSource || !mContainer)
 
307
        return NS_ERROR_NOT_INITIALIZED;
 
308
 
 
309
    NS_PRECONDITION(aElement != nsnull, "null ptr");
 
310
    if (! aElement)
 
311
        return NS_ERROR_NULL_POINTER;
 
312
 
 
313
    NS_PRECONDITION(aIndex >= 1, "illegal value");
 
314
    if (aIndex < 1)
 
315
        return NS_ERROR_ILLEGAL_VALUE;
 
316
 
 
317
    nsresult rv;
 
318
 
 
319
    PRInt32 count;
 
320
    rv = GetCount(&count);
 
321
    if (NS_FAILED(rv)) return rv;
 
322
 
 
323
    NS_ASSERTION(aIndex <= count + 1, "illegal value");
 
324
    if (aIndex > count + 1)
 
325
        return NS_ERROR_ILLEGAL_VALUE;
 
326
 
 
327
    if (aRenumber) {
 
328
        // Make a hole for the element. This will have the side effect of
 
329
        // completely renumbering the container from 'aIndex' to 'count',
 
330
        // and will spew assertions.
 
331
        rv = Renumber(aIndex, +1);
 
332
        if (NS_FAILED(rv)) return rv;
 
333
    }
 
334
 
 
335
    nsCOMPtr<nsIRDFResource> ordinal;
 
336
    rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal));
 
337
    if (NS_FAILED(rv)) return rv;
 
338
 
 
339
    rv = mDataSource->Assert(mContainer, ordinal, aElement, PR_TRUE);
 
340
    if (NS_FAILED(rv)) return rv;
 
341
 
 
342
    return NS_OK;
 
343
}
 
344
 
 
345
NS_IMETHODIMP
 
346
RDFContainerImpl::RemoveElementAt(PRInt32 aIndex, PRBool aRenumber, nsIRDFNode** _retval)
 
347
{
 
348
    if (!mDataSource || !mContainer)
 
349
        return NS_ERROR_NOT_INITIALIZED;
 
350
 
 
351
    *_retval = nsnull;
 
352
 
 
353
    if (aIndex< 1)
 
354
        return NS_ERROR_ILLEGAL_VALUE;
 
355
 
 
356
    nsresult rv;
 
357
 
 
358
    PRInt32 count;
 
359
    rv = GetCount(&count);
 
360
    if (NS_FAILED(rv)) return rv;
 
361
 
 
362
    if (aIndex > count)
 
363
        return NS_ERROR_ILLEGAL_VALUE;
 
364
 
 
365
    nsCOMPtr<nsIRDFResource> ordinal;
 
366
    rv = gRDFContainerUtils->IndexToOrdinalResource(aIndex, getter_AddRefs(ordinal));
 
367
    if (NS_FAILED(rv)) return rv;
 
368
 
 
369
    nsCOMPtr<nsIRDFNode> old;
 
370
    rv = mDataSource->GetTarget(mContainer, ordinal, PR_TRUE, getter_AddRefs(old));
 
371
    if (NS_FAILED(rv)) return rv;
 
372
 
 
373
    if (rv == NS_OK) {
 
374
        rv = mDataSource->Unassert(mContainer, ordinal, old);
 
375
        if (NS_FAILED(rv)) return rv;
 
376
 
 
377
        if (aRenumber) {
 
378
            // Now slide the rest of the collection backwards to fill in
 
379
            // the gap. This will have the side effect of completely
 
380
            // renumber the container from index to the end.
 
381
            rv = Renumber(aIndex + 1, -1);
 
382
            if (NS_FAILED(rv)) return rv;
 
383
        }
 
384
    }
 
385
 
 
386
    *_retval = old;
 
387
    NS_ADDREF(*_retval);
 
388
 
 
389
    return NS_OK;
 
390
}
 
391
 
 
392
NS_IMETHODIMP
 
393
RDFContainerImpl::IndexOf(nsIRDFNode *aElement, PRInt32 *aIndex)
 
394
{
 
395
    if (!mDataSource || !mContainer)
 
396
        return NS_ERROR_NOT_INITIALIZED;
 
397
 
 
398
    return gRDFContainerUtils->IndexOf(mDataSource, mContainer,
 
399
                                       aElement, aIndex);
 
400
}
 
401
 
 
402
 
 
403
////////////////////////////////////////////////////////////////////////
 
404
 
 
405
 
 
406
RDFContainerImpl::RDFContainerImpl()
 
407
    : mDataSource(nsnull), mContainer(nsnull)
 
408
{
 
409
}
 
410
 
 
411
 
 
412
nsresult
 
413
RDFContainerImpl::Init()
 
414
{
 
415
    if (gRefCnt++ == 0) {
 
416
        nsresult rv;
 
417
 
 
418
        rv = nsServiceManager::GetService(kRDFServiceCID,
 
419
                                          NS_GET_IID(nsIRDFService),
 
420
                                          (nsISupports**) &gRDFService);
 
421
 
 
422
        NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF service");
 
423
        if (NS_FAILED(rv)) return rv;
 
424
 
 
425
        rv = gRDFService->GetResource(NS_LITERAL_CSTRING(RDF_NAMESPACE_URI "nextVal"),
 
426
                                      &kRDF_nextVal);
 
427
        if (NS_FAILED(rv)) return rv;
 
428
 
 
429
        rv = nsServiceManager::GetService(kRDFContainerUtilsCID,
 
430
                                          NS_GET_IID(nsIRDFContainerUtils),
 
431
                                          (nsISupports**) &gRDFContainerUtils);
 
432
 
 
433
        NS_ASSERTION(NS_SUCCEEDED(rv), "unable to get RDF container utils service");
 
434
        if (NS_FAILED(rv)) return rv;
 
435
    }
 
436
 
 
437
    return NS_OK;
 
438
}
 
439
 
 
440
 
 
441
RDFContainerImpl::~RDFContainerImpl()
 
442
{
 
443
#ifdef DEBUG_REFS
 
444
    --gInstanceCount;
 
445
    fprintf(stdout, "%d - RDF: RDFContainerImpl\n", gInstanceCount);
 
446
#endif
 
447
 
 
448
    NS_IF_RELEASE(mContainer);
 
449
    NS_IF_RELEASE(mDataSource);
 
450
 
 
451
    if (--gRefCnt == 0) {
 
452
        if (gRDFContainerUtils) {
 
453
            nsServiceManager::ReleaseService(kRDFContainerUtilsCID, gRDFContainerUtils);
 
454
            gRDFContainerUtils = nsnull;
 
455
        }
 
456
 
 
457
        if (gRDFService) {
 
458
            nsServiceManager::ReleaseService(kRDFServiceCID, gRDFService);
 
459
            gRDFService = nsnull;
 
460
        }
 
461
 
 
462
        NS_IF_RELEASE(kRDF_nextVal);
 
463
    }
 
464
}
 
465
 
 
466
 
 
467
nsresult
 
468
NS_NewRDFContainer(nsIRDFContainer** aResult)
 
469
{
 
470
    RDFContainerImpl* result = new RDFContainerImpl();
 
471
    if (! result)
 
472
        return NS_ERROR_OUT_OF_MEMORY;
 
473
 
 
474
    nsresult rv;
 
475
    rv = result->Init();
 
476
    if (NS_FAILED(rv)) {
 
477
        delete result;
 
478
        return rv;
 
479
    }
 
480
 
 
481
    NS_ADDREF(result);
 
482
    *aResult = result;
 
483
    return NS_OK;
 
484
}
 
485
 
 
486
 
 
487
nsresult
 
488
NS_NewRDFContainer(nsIRDFDataSource* aDataSource,
 
489
                   nsIRDFResource* aResource,
 
490
                   nsIRDFContainer** aResult)
 
491
{
 
492
    nsresult rv;
 
493
    rv = NS_NewRDFContainer(aResult);
 
494
    if (NS_FAILED(rv)) return rv;
 
495
 
 
496
    rv = (*aResult)->Init(aDataSource, aResource);
 
497
    if (NS_FAILED(rv)) {
 
498
        NS_RELEASE(*aResult);
 
499
    }
 
500
    return rv;
 
501
}
 
502
 
 
503
 
 
504
nsresult
 
505
RDFContainerImpl::Renumber(PRInt32 aStartIndex, PRInt32 aIncrement)
 
506
{
 
507
    if (!mDataSource || !mContainer)
 
508
        return NS_ERROR_NOT_INITIALIZED;
 
509
 
 
510
    // Renumber the elements in the container starting with
 
511
    // aStartIndex, updating each element's index by aIncrement. For
 
512
    // example,
 
513
    //
 
514
    //   (1:a 2:b 3:c)
 
515
    //   Renumber(2, +1);
 
516
    //   (1:a 3:b 4:c)
 
517
    //   Renumber(3, -1);
 
518
    //   (1:a 2:b 3:c)
 
519
    //
 
520
    nsresult rv;
 
521
 
 
522
    if (! aIncrement)
 
523
        return NS_OK;
 
524
 
 
525
    PRInt32 count;
 
526
    rv = GetCount(&count);
 
527
    if (NS_FAILED(rv)) return rv;
 
528
 
 
529
    if (aIncrement > 0) {
 
530
        // Update the container's nextVal to reflect the
 
531
        // renumbering. We do this now if aIncrement > 0 because we'll
 
532
        // want to be able to acknowledge that new elements are in the
 
533
        // container.
 
534
        rv = SetNextValue(count + aIncrement + 1);
 
535
        if (NS_FAILED(rv)) return rv;
 
536
    }
 
537
 
 
538
    PRInt32 i;
 
539
    if (aIncrement < 0) {
 
540
        i = aStartIndex;
 
541
    }
 
542
    else {
 
543
        i = count; // we're one-indexed.
 
544
    }
 
545
 
 
546
    // Note: once we disable notifications, don't exit this method until
 
547
    // enabling notifications
 
548
    nsCOMPtr<nsIRDFPropagatableDataSource> propagatable =
 
549
        do_QueryInterface(mDataSource);
 
550
    if (propagatable) {
 
551
        propagatable->SetPropagateChanges(PR_FALSE);
 
552
    }
 
553
 
 
554
    PRBool  err = PR_FALSE;
 
555
    while ((err == PR_FALSE) && ((aIncrement < 0) ? (i <= count) : (i >= aStartIndex)))
 
556
    {
 
557
        nsCOMPtr<nsIRDFResource> oldOrdinal;
 
558
        rv = gRDFContainerUtils->IndexToOrdinalResource(i, getter_AddRefs(oldOrdinal));
 
559
        if (NS_FAILED(rv))
 
560
        {
 
561
            err = PR_TRUE;
 
562
            continue;
 
563
        }
 
564
 
 
565
        nsCOMPtr<nsIRDFResource> newOrdinal;
 
566
        rv = gRDFContainerUtils->IndexToOrdinalResource(i + aIncrement, getter_AddRefs(newOrdinal));
 
567
        if (NS_FAILED(rv))
 
568
        {
 
569
            err = PR_TRUE;
 
570
            continue;
 
571
        }
 
572
 
 
573
        // Because of aggregation, we need to be paranoid about the
 
574
        // possibility that >1 element may be present per ordinal. If
 
575
        // there _is_ in fact more than one element, they'll all get
 
576
        // assigned to the same new ordinal; i.e., we don't make any
 
577
        // attempt to "clean up" the duplicate numbering. (Doing so
 
578
        // would require two passes.)
 
579
        nsCOMPtr<nsISimpleEnumerator> targets;
 
580
        rv = mDataSource->GetTargets(mContainer, oldOrdinal, PR_TRUE, getter_AddRefs(targets));
 
581
        if (NS_FAILED(rv))
 
582
        {
 
583
            err = PR_TRUE;
 
584
            continue;
 
585
        }
 
586
 
 
587
        while (1) {
 
588
            PRBool hasMore;
 
589
            rv = targets->HasMoreElements(&hasMore);
 
590
            if (NS_FAILED(rv))
 
591
            {
 
592
                err = PR_TRUE;
 
593
                break;
 
594
            }
 
595
 
 
596
            if (! hasMore)
 
597
                break;
 
598
 
 
599
            nsCOMPtr<nsISupports> isupports;
 
600
            rv = targets->GetNext(getter_AddRefs(isupports));
 
601
            if (NS_FAILED(rv))
 
602
            {
 
603
                err = PR_TRUE;
 
604
                break;
 
605
            }
 
606
 
 
607
            nsCOMPtr<nsIRDFNode> element( do_QueryInterface(isupports) );
 
608
            NS_ASSERTION(element != nsnull, "something funky in the enumerator");
 
609
            if (! element)
 
610
            {
 
611
                err = PR_TRUE;
 
612
                rv = NS_ERROR_UNEXPECTED;
 
613
                break;
 
614
            }
 
615
 
 
616
            rv = mDataSource->Unassert(mContainer, oldOrdinal, element);
 
617
            if (NS_FAILED(rv))
 
618
            {
 
619
                err = PR_TRUE;
 
620
                break;
 
621
            }
 
622
 
 
623
            rv = mDataSource->Assert(mContainer, newOrdinal, element, PR_TRUE);
 
624
            if (NS_FAILED(rv))
 
625
            {
 
626
                err = PR_TRUE;
 
627
                break;
 
628
            }
 
629
        }
 
630
 
 
631
        i -= aIncrement;
 
632
    }
 
633
 
 
634
    if ((err == PR_FALSE) && (aIncrement < 0))
 
635
    {
 
636
        // Update the container's nextVal to reflect the
 
637
        // renumbering. We do this now if aIncrement < 0 because, up
 
638
        // until this point, we'll want people to be able to find
 
639
        // things that are still "at the end".
 
640
        rv = SetNextValue(count + aIncrement + 1);
 
641
        if (NS_FAILED(rv))
 
642
        {
 
643
            err = PR_TRUE;
 
644
        }
 
645
    }
 
646
 
 
647
    // Note: MUST enable notifications before exiting this method
 
648
    if (propagatable) {
 
649
        propagatable->SetPropagateChanges(PR_TRUE);
 
650
    }
 
651
 
 
652
    if (err == PR_TRUE) return(rv);
 
653
 
 
654
    return NS_OK;
 
655
}
 
656
 
 
657
 
 
658
 
 
659
nsresult
 
660
RDFContainerImpl::SetNextValue(PRInt32 aIndex)
 
661
{
 
662
    if (!mDataSource || !mContainer)
 
663
        return NS_ERROR_NOT_INITIALIZED;
 
664
 
 
665
    nsresult rv;
 
666
 
 
667
    // Remove the current value of nextVal, if there is one.
 
668
    nsCOMPtr<nsIRDFNode> nextValNode;
 
669
    if (NS_SUCCEEDED(rv = mDataSource->GetTarget(mContainer,
 
670
                                                 kRDF_nextVal,
 
671
                                                 PR_TRUE,
 
672
                                                 getter_AddRefs(nextValNode)))) {
 
673
        if (NS_FAILED(rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValNode))) {
 
674
            NS_ERROR("unable to update nextVal");
 
675
            return rv;
 
676
        }
 
677
    }
 
678
 
 
679
    nsAutoString s;
 
680
    s.AppendInt(aIndex, 10);
 
681
 
 
682
    nsCOMPtr<nsIRDFLiteral> nextVal;
 
683
    if (NS_FAILED(rv = gRDFService->GetLiteral(s.get(), getter_AddRefs(nextVal)))) {
 
684
        NS_ERROR("unable to get nextVal literal");
 
685
        return rv;
 
686
    }
 
687
 
 
688
    rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextVal, PR_TRUE);
 
689
    if (rv != NS_RDF_ASSERTION_ACCEPTED) {
 
690
        NS_ERROR("unable to update nextVal");
 
691
        return NS_ERROR_FAILURE;
 
692
    }
 
693
 
 
694
    return NS_OK;
 
695
}
 
696
 
 
697
 
 
698
nsresult
 
699
RDFContainerImpl::GetNextValue(nsIRDFResource** aResult)
 
700
{
 
701
    if (!mDataSource || !mContainer)
 
702
        return NS_ERROR_NOT_INITIALIZED;
 
703
 
 
704
    nsresult rv;
 
705
 
 
706
    // Get the next value, which hangs off of the bag via the
 
707
    // RDF:nextVal property.
 
708
    nsCOMPtr<nsIRDFNode> nextValNode;
 
709
    rv = mDataSource->GetTarget(mContainer, kRDF_nextVal, PR_TRUE, getter_AddRefs(nextValNode));
 
710
    if (NS_FAILED(rv)) return rv;
 
711
 
 
712
    if (rv == NS_RDF_NO_VALUE)
 
713
        return NS_ERROR_UNEXPECTED;
 
714
 
 
715
    nsCOMPtr<nsIRDFLiteral> nextValLiteral;
 
716
    rv = nextValNode->QueryInterface(NS_GET_IID(nsIRDFLiteral), getter_AddRefs(nextValLiteral));
 
717
    if (NS_FAILED(rv)) return rv;
 
718
 
 
719
    const PRUnichar* s;
 
720
    rv = nextValLiteral->GetValueConst(&s);
 
721
    if (NS_FAILED(rv)) return rv;
 
722
 
 
723
    PRInt32 nextVal = 0;
 
724
    {
 
725
        for (const PRUnichar* p = s; *p != 0; ++p) {
 
726
            NS_ASSERTION(*p >= '0' && *p <= '9', "not a digit");
 
727
            if (*p < '0' || *p > '9')
 
728
                break;
 
729
 
 
730
            nextVal *= 10;
 
731
            nextVal += *p - '0';
 
732
        }
 
733
    }
 
734
 
 
735
    char buf[sizeof(kRDFNameSpaceURI) + 16];
 
736
    nsFixedCString nextValStr(buf, sizeof(buf), 0);
 
737
    nextValStr = kRDFNameSpaceURI;
 
738
    nextValStr.Append("_");
 
739
    nextValStr.AppendInt(nextVal, 10);
 
740
 
 
741
    rv = gRDFService->GetResource(nextValStr, aResult);
 
742
    if (NS_FAILED(rv)) return rv;
 
743
 
 
744
    // Now increment the RDF:nextVal property.
 
745
    rv = mDataSource->Unassert(mContainer, kRDF_nextVal, nextValLiteral);
 
746
    if (NS_FAILED(rv)) return rv;
 
747
 
 
748
    ++nextVal;
 
749
    nextValStr.Truncate();
 
750
    nextValStr.AppendInt(nextVal, 10);
 
751
 
 
752
    rv = gRDFService->GetLiteral(NS_ConvertASCIItoUCS2(nextValStr).get(), getter_AddRefs(nextValLiteral));
 
753
    if (NS_FAILED(rv)) return rv;
 
754
 
 
755
    rv = mDataSource->Assert(mContainer, kRDF_nextVal, nextValLiteral, PR_TRUE);
 
756
    if (NS_FAILED(rv)) return rv;
 
757
 
 
758
    if (RDF_SEQ_LIST_LIMIT == nextVal)
 
759
    {
 
760
        // focal point for RDF container mutation;
 
761
        // basically, provide a hint to allow for fast access
 
762
        nsCOMPtr<nsIRDFInMemoryDataSource> inMem = do_QueryInterface(mDataSource);
 
763
        if (inMem)
 
764
        {
 
765
            // ignore error; failure just means slower access
 
766
            (void)inMem->EnsureFastContainment(mContainer);
 
767
        }
 
768
    }
 
769
 
 
770
    return NS_OK;
 
771
}