1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6 #ifndef _MDB_
7 # include "mdb.h"
8 #endif
9
10 #ifndef _MORK_
11 # include "mork.h"
12 #endif
13
14 #ifndef _MORKNODE_
15 # include "morkNode.h"
16 #endif
17
18 #ifndef _MORKROWOBJECT_
19 # include "morkRowObject.h"
20 #endif
21
22 #ifndef _MORKENV_
23 # include "morkEnv.h"
24 #endif
25
26 #ifndef _MORKSTORE_
27 # include "morkStore.h"
28 #endif
29
30 #ifndef _MORKROWCELLCURSOR_
31 # include "morkRowCellCursor.h"
32 #endif
33
34 #ifndef _MORKCELLOBJECT_
35 # include "morkCellObject.h"
36 #endif
37
38 #ifndef _MORKROW_
39 # include "morkRow.h"
40 #endif
41
42 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
43
44 // ````` ````` ````` ````` `````
45 // { ===== begin morkNode interface =====
46
CloseMorkNode(morkEnv * ev)47 /*public virtual*/ void morkRowObject::CloseMorkNode(
48 morkEnv* ev) // CloseRowObject() only if open
49 {
50 if (this->IsOpenNode()) {
51 this->MarkClosing();
52 this->CloseRowObject(ev);
53 this->MarkShut();
54 }
55 }
56
57 /*public virtual*/
~morkRowObject()58 morkRowObject::~morkRowObject() // assert CloseRowObject() executed earlier
59 {
60 CloseMorkNode(mMorkEnv);
61 MORK_ASSERT(this->IsShutNode());
62 }
63
64 /*public non-poly*/
morkRowObject(morkEnv * ev,const morkUsage & inUsage,nsIMdbHeap * ioHeap,morkRow * ioRow,morkStore * ioStore)65 morkRowObject::morkRowObject(morkEnv* ev, const morkUsage& inUsage,
66 nsIMdbHeap* ioHeap, morkRow* ioRow,
67 morkStore* ioStore)
68 : morkObject(ev, inUsage, ioHeap, morkColor_kNone, (morkHandle*)0),
69 mRowObject_Row(0),
70 mRowObject_Store(0) {
71 if (ev->Good()) {
72 if (ioRow && ioStore) {
73 mRowObject_Row = ioRow;
74 mRowObject_Store =
75 ioStore; // morkRowObjects don't ref-cnt the owning store.
76
77 if (ev->Good()) mNode_Derived = morkDerived_kRowObject;
78 } else
79 ev->NilPointerError();
80 }
81 }
82
NS_IMPL_ISUPPORTS_INHERITED(morkRowObject,morkObject,nsIMdbRow)83 NS_IMPL_ISUPPORTS_INHERITED(morkRowObject, morkObject, nsIMdbRow)
84 // { ===== begin nsIMdbCollection methods =====
85
86 // { ----- begin attribute methods -----
87 NS_IMETHODIMP
88 morkRowObject::GetSeed(nsIMdbEnv* mev, mdb_seed* outSeed) {
89 nsresult outErr = NS_OK;
90 morkEnv* ev = morkEnv::FromMdbEnv(mev);
91 if (ev) {
92 *outSeed = (mdb_seed)mRowObject_Row->mRow_Seed;
93 outErr = ev->AsErr();
94 }
95 return outErr;
96 }
97 NS_IMETHODIMP
GetCount(nsIMdbEnv * mev,mdb_count * outCount)98 morkRowObject::GetCount(nsIMdbEnv* mev, mdb_count* outCount) {
99 nsresult outErr = NS_OK;
100 morkEnv* ev = morkEnv::FromMdbEnv(mev);
101 if (ev) {
102 *outCount = (mdb_count)mRowObject_Row->mRow_Length;
103 outErr = ev->AsErr();
104 }
105 return outErr;
106 }
107
108 NS_IMETHODIMP
GetPort(nsIMdbEnv * mev,nsIMdbPort ** acqPort)109 morkRowObject::GetPort(nsIMdbEnv* mev, nsIMdbPort** acqPort) {
110 nsresult outErr = NS_OK;
111 nsIMdbPort* outPort = 0;
112 morkEnv* ev = morkEnv::FromMdbEnv(mev);
113 if (ev) {
114 morkRowSpace* rowSpace = mRowObject_Row->mRow_Space;
115 if (rowSpace && rowSpace->mSpace_Store) {
116 morkStore* store = mRowObject_Row->GetRowSpaceStore(ev);
117 if (store) outPort = store->AcquireStoreHandle(ev);
118 } else
119 ev->NilPointerError();
120
121 outErr = ev->AsErr();
122 }
123 if (acqPort) *acqPort = outPort;
124
125 return outErr;
126 }
127 // } ----- end attribute methods -----
128
129 // { ----- begin cursor methods -----
130 NS_IMETHODIMP
GetCursor(nsIMdbEnv * mev,mdb_pos inMemberPos,nsIMdbCursor ** acqCursor)131 morkRowObject::GetCursor( // make a cursor starting iter at inMemberPos
132 nsIMdbEnv* mev, // context
133 mdb_pos inMemberPos, // zero-based ordinal pos of member in collection
134 nsIMdbCursor** acqCursor) {
135 return this->GetRowCellCursor(mev, inMemberPos,
136 (nsIMdbRowCellCursor**)acqCursor);
137 }
138 // } ----- end cursor methods -----
139
140 // { ----- begin ID methods -----
141 NS_IMETHODIMP
GetOid(nsIMdbEnv * mev,mdbOid * outOid)142 morkRowObject::GetOid(nsIMdbEnv* mev, mdbOid* outOid) {
143 *outOid = mRowObject_Row->mRow_Oid;
144 morkEnv* ev = morkEnv::FromMdbEnv(mev);
145 return (ev) ? ev->AsErr() : NS_ERROR_FAILURE;
146 }
147
148 NS_IMETHODIMP
BecomeContent(nsIMdbEnv * mev,const mdbOid * inOid)149 morkRowObject::BecomeContent(nsIMdbEnv* mev, const mdbOid* inOid) {
150 NS_ASSERTION(false, "not implemented");
151 return NS_ERROR_NOT_IMPLEMENTED;
152 // remember row->MaybeDirtySpaceStoreAndRow();
153 }
154 // } ----- end ID methods -----
155
156 // { ----- begin activity dropping methods -----
157 NS_IMETHODIMP
DropActivity(nsIMdbEnv * mev)158 morkRowObject::DropActivity( // tell collection usage no longer expected
159 nsIMdbEnv* mev) {
160 NS_ASSERTION(false, "not implemented");
161 return NS_ERROR_NOT_IMPLEMENTED;
162 }
163 // } ----- end activity dropping methods -----
164
165 // } ===== end nsIMdbCollection methods =====
166
167 // { ===== begin nsIMdbRow methods =====
168
169 // { ----- begin cursor methods -----
170 NS_IMETHODIMP
GetRowCellCursor(nsIMdbEnv * mev,mdb_pos inPos,nsIMdbRowCellCursor ** acqCursor)171 morkRowObject::GetRowCellCursor( // make a cursor starting iteration at
172 // inCellPos
173 nsIMdbEnv* mev, // context
174 mdb_pos inPos, // zero-based ordinal position of cell in row
175 nsIMdbRowCellCursor** acqCursor) {
176 nsresult outErr = NS_OK;
177 morkEnv* ev = morkEnv::FromMdbEnv(mev);
178 nsIMdbRowCellCursor* outCursor = 0;
179 if (ev) {
180 morkRowCellCursor* cursor = mRowObject_Row->NewRowCellCursor(ev, inPos);
181 if (cursor) {
182 if (ev->Good()) {
183 cursor->mCursor_Seed = (mork_seed)inPos;
184 outCursor = cursor;
185 NS_ADDREF(cursor);
186 }
187 }
188 outErr = ev->AsErr();
189 }
190 if (acqCursor) *acqCursor = outCursor;
191 return outErr;
192 }
193 // } ----- end cursor methods -----
194
195 // { ----- begin column methods -----
196 NS_IMETHODIMP
AddColumn(nsIMdbEnv * mev,mdb_column inColumn,const mdbYarn * inYarn)197 morkRowObject::AddColumn( // make sure a particular column is inside row
198 nsIMdbEnv* mev, // context
199 mdb_column inColumn, // column to add
200 const mdbYarn* inYarn) {
201 nsresult outErr = NS_ERROR_FAILURE;
202 morkEnv* ev = morkEnv::FromMdbEnv(mev);
203 if (ev) {
204 if (mRowObject_Store && mRowObject_Row)
205 mRowObject_Row->AddColumn(ev, inColumn, inYarn, mRowObject_Store);
206
207 outErr = ev->AsErr();
208 }
209 return outErr;
210 }
211
212 NS_IMETHODIMP
CutColumn(nsIMdbEnv * mev,mdb_column inColumn)213 morkRowObject::CutColumn( // make sure a column is absent from the row
214 nsIMdbEnv* mev, // context
215 mdb_column inColumn) {
216 nsresult outErr = NS_ERROR_FAILURE;
217 morkEnv* ev = morkEnv::FromMdbEnv(mev);
218 if (ev) {
219 mRowObject_Row->CutColumn(ev, inColumn);
220 outErr = ev->AsErr();
221 }
222 return outErr;
223 }
224
225 NS_IMETHODIMP
CutAllColumns(nsIMdbEnv * mev)226 morkRowObject::CutAllColumns( // remove all columns from the row
227 nsIMdbEnv* mev) {
228 nsresult outErr = NS_OK;
229 morkEnv* ev = morkEnv::FromMdbEnv(mev);
230 if (ev) {
231 mRowObject_Row->CutAllColumns(ev);
232 outErr = ev->AsErr();
233 }
234 return outErr;
235 }
236 // } ----- end column methods -----
237
238 // { ----- begin cell methods -----
239 NS_IMETHODIMP
NewCell(nsIMdbEnv * mev,mdb_column inColumn,nsIMdbCell ** acqCell)240 morkRowObject::NewCell( // get cell for specified column, or add new one
241 nsIMdbEnv* mev, // context
242 mdb_column inColumn, // column to add
243 nsIMdbCell** acqCell) {
244 nsresult outErr = NS_OK;
245 morkEnv* ev = morkEnv::FromMdbEnv(mev);
246 if (ev) {
247 GetCell(mev, inColumn, acqCell);
248 if (!*acqCell) {
249 if (mRowObject_Store) {
250 mdbYarn yarn; // to pass empty yarn into morkRowObject::AddColumn()
251 yarn.mYarn_Buf = 0;
252 yarn.mYarn_Fill = 0;
253 yarn.mYarn_Size = 0;
254 yarn.mYarn_More = 0;
255 yarn.mYarn_Form = 0;
256 yarn.mYarn_Grow = 0;
257 AddColumn(ev, inColumn, &yarn);
258 GetCell(mev, inColumn, acqCell);
259 }
260 }
261
262 outErr = ev->AsErr();
263 }
264 return outErr;
265 }
266
267 NS_IMETHODIMP
AddCell(nsIMdbEnv * mev,const nsIMdbCell * inCell)268 morkRowObject::AddCell( // copy a cell from another row to this row
269 nsIMdbEnv* mev, // context
270 const nsIMdbCell* inCell) {
271 nsresult outErr = NS_OK;
272 morkEnv* ev = morkEnv::FromMdbEnv(mev);
273 if (ev) {
274 morkCell* cell = 0;
275 morkCellObject* cellObj = (morkCellObject*)inCell;
276 if (cellObj->CanUseCell(mev, morkBool_kFalse, &outErr, &cell)) {
277 morkRow* cellRow = cellObj->mCellObject_Row;
278 if (cellRow) {
279 if (mRowObject_Row != cellRow) {
280 morkStore* store = mRowObject_Row->GetRowSpaceStore(ev);
281 morkStore* cellStore = cellRow->GetRowSpaceStore(ev);
282 if (store && cellStore) {
283 mork_column col = cell->GetColumn();
284 morkAtom* atom = cell->mCell_Atom;
285 mdbYarn yarn;
286 morkAtom::AliasYarn(atom, &yarn); // works even when atom is nil
287
288 if (store != cellStore) col = store->CopyToken(ev, col, cellStore);
289 if (ev->Good()) AddColumn(ev, col, &yarn);
290 } else
291 ev->NilPointerError();
292 }
293 } else
294 ev->NilPointerError();
295 }
296
297 outErr = ev->AsErr();
298 }
299 return outErr;
300 }
301
302 NS_IMETHODIMP
GetCell(nsIMdbEnv * mev,mdb_column inColumn,nsIMdbCell ** acqCell)303 morkRowObject::GetCell( // find a cell in this row
304 nsIMdbEnv* mev, // context
305 mdb_column inColumn, // column to find
306 nsIMdbCell** acqCell) {
307 nsresult outErr = NS_OK;
308 nsIMdbCell* outCell = 0;
309 morkEnv* ev = morkEnv::FromMdbEnv(mev);
310
311 if (ev) {
312 if (inColumn) {
313 mork_pos pos = 0;
314 morkCell* cell = mRowObject_Row->GetCell(ev, inColumn, &pos);
315 if (cell) {
316 outCell = mRowObject_Row->AcquireCellHandle(ev, cell, inColumn, pos);
317 }
318 } else
319 mRowObject_Row->ZeroColumnError(ev);
320
321 outErr = ev->AsErr();
322 }
323 if (acqCell) *acqCell = outCell;
324 return outErr;
325 }
326
327 NS_IMETHODIMP
EmptyAllCells(nsIMdbEnv * mev)328 morkRowObject::EmptyAllCells( // make all cells in row empty of content
329 nsIMdbEnv* mev) {
330 nsresult outErr = NS_OK;
331 morkEnv* ev = morkEnv::FromMdbEnv(mev);
332 if (ev) {
333 EmptyAllCells(ev);
334 outErr = ev->AsErr();
335 }
336 return outErr;
337 }
338 // } ----- end cell methods -----
339
340 // { ----- begin row methods -----
341 NS_IMETHODIMP
AddRow(nsIMdbEnv * mev,nsIMdbRow * ioSourceRow)342 morkRowObject::AddRow( // add all cells in another row to this one
343 nsIMdbEnv* mev, // context
344 nsIMdbRow* ioSourceRow) {
345 nsresult outErr = NS_OK;
346 morkEnv* ev = morkEnv::FromMdbEnv(mev);
347 if (ev) {
348 morkRow* unsafeSource = (morkRow*)ioSourceRow; // unsafe cast
349 // if ( unsafeSource->CanUseRow(mev, morkBool_kFalse, &outErr, &source) )
350 { mRowObject_Row->AddRow(ev, unsafeSource); }
351 outErr = ev->AsErr();
352 }
353 return outErr;
354 }
355
356 NS_IMETHODIMP
SetRow(nsIMdbEnv * mev,nsIMdbRow * ioSourceRow)357 morkRowObject::SetRow( // make exact duplicate of another row
358 nsIMdbEnv* mev, // context
359 nsIMdbRow* ioSourceRow) {
360 nsresult outErr = NS_OK;
361 morkEnv* ev = morkEnv::FromMdbEnv(mev);
362 if (ev) {
363 morkRowObject* sourceObject = (morkRowObject*)ioSourceRow; // unsafe cast
364 morkRow* unsafeSource = sourceObject->mRowObject_Row;
365 // if ( unsafeSource->CanUseRow(mev, morkBool_kFalse, &outErr, &source) )
366 { mRowObject_Row->SetRow(ev, unsafeSource); }
367 outErr = ev->AsErr();
368 }
369 return outErr;
370 }
371 // } ----- end row methods -----
372
373 // { ----- begin blob methods -----
374 NS_IMETHODIMP
SetCellYarn(nsIMdbEnv * mev,mdb_column inColumn,const mdbYarn * inYarn)375 morkRowObject::SetCellYarn( // synonym for AddColumn()
376 nsIMdbEnv* mev, // context
377 mdb_column inColumn, // column to add
378 const mdbYarn* inYarn) {
379 nsresult outErr = NS_OK;
380 morkEnv* ev = morkEnv::FromMdbEnv(mev);
381 if (ev) {
382 if (mRowObject_Store) AddColumn(ev, inColumn, inYarn);
383
384 outErr = ev->AsErr();
385 }
386 return outErr;
387 }
388 NS_IMETHODIMP
GetCellYarn(nsIMdbEnv * mev,mdb_column inColumn,mdbYarn * outYarn)389 morkRowObject::GetCellYarn(nsIMdbEnv* mev, // context
390 mdb_column inColumn, // column to read
391 mdbYarn* outYarn) // writes some yarn slots
392 // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
393 {
394 nsresult outErr = NS_OK;
395 morkEnv* ev = morkEnv::FromMdbEnv(mev);
396 if (ev) {
397 if (mRowObject_Store && mRowObject_Row) {
398 morkAtom* atom = mRowObject_Row->GetColumnAtom(ev, inColumn);
399 morkAtom::GetYarn(atom, outYarn);
400 }
401
402 outErr = ev->AsErr();
403 }
404 return outErr;
405 }
406
407 NS_IMETHODIMP
AliasCellYarn(nsIMdbEnv * mev,mdb_column inColumn,mdbYarn * outYarn)408 morkRowObject::AliasCellYarn(nsIMdbEnv* mev, // context
409 mdb_column inColumn, // column to alias
410 mdbYarn* outYarn) // writes ALL yarn slots
411 {
412 nsresult outErr = NS_OK;
413 morkEnv* ev = morkEnv::FromMdbEnv(mev);
414 if (ev) {
415 if (mRowObject_Store && mRowObject_Row) {
416 morkAtom* atom = mRowObject_Row->GetColumnAtom(ev, inColumn);
417 morkAtom::AliasYarn(atom, outYarn);
418 // note nil atom works and sets yarn correctly
419 }
420 outErr = ev->AsErr();
421 }
422 return outErr;
423 }
424
425 NS_IMETHODIMP
NextCellYarn(nsIMdbEnv * mev,mdb_column * ioColumn,mdbYarn * outYarn)426 morkRowObject::NextCellYarn(
427 nsIMdbEnv* mev, // iterative version of GetCellYarn()
428 mdb_column* ioColumn, // next column to read
429 mdbYarn* outYarn) // writes some yarn slots
430 // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
431 //
432 // The ioColumn argument is an inout parameter which initially contains the
433 // last column accessed and returns the next column corresponding to the
434 // content read into the yarn. Callers should start with a zero column
435 // value to say 'no previous column', which causes the first column to be
436 // read. Then the value returned in ioColumn is perfect for the next call
437 // to NextCellYarn(), since it will then be the previous column accessed.
438 // Callers need only examine the column token returned to see which cell
439 // in the row is being read into the yarn. When no more columns remain,
440 // and the iteration has ended, ioColumn will return a zero token again.
441 // So iterating over cells starts and ends with a zero column token.
442 {
443 nsresult outErr = NS_OK;
444 morkEnv* ev = morkEnv::FromMdbEnv(mev);
445 if (ev) {
446 if (mRowObject_Store && mRowObject_Row)
447 mRowObject_Row->NextColumn(ev, ioColumn, outYarn);
448
449 outErr = ev->AsErr();
450 }
451 return outErr;
452 }
453
454 NS_IMETHODIMP
SeekCellYarn(nsIMdbEnv * mev,mdb_pos inPos,mdb_column * outColumn,mdbYarn * outYarn)455 morkRowObject::SeekCellYarn( // resembles nsIMdbRowCellCursor::SeekCell()
456 nsIMdbEnv* mev, // context
457 mdb_pos inPos, // position of cell in row sequence
458 mdb_column* outColumn, // column for this particular cell
459 mdbYarn* outYarn) // writes some yarn slots
460 // copy content into the yarn buffer, and update mYarn_Fill and mYarn_Form
461 // Callers can pass nil for outYarn to indicate no interest in content, so
462 // only the outColumn value is returned. NOTE to subclasses: you must be
463 // able to ignore outYarn when the pointer is nil; please do not crash.
464
465 {
466 nsresult outErr = NS_OK;
467 morkEnv* ev = morkEnv::FromMdbEnv(mev);
468 if (ev) {
469 if (mRowObject_Store && mRowObject_Row)
470 mRowObject_Row->SeekColumn(ev, inPos, outColumn, outYarn);
471
472 outErr = ev->AsErr();
473 }
474 return outErr;
475 }
476
477 // } ----- end blob methods -----
478
479 // } ===== end nsIMdbRow methods =====
480
CloseRowObject(morkEnv * ev)481 /*public non-poly*/ void morkRowObject::CloseRowObject(
482 morkEnv* ev) // called by CloseMorkNode();
483 {
484 if (this->IsNode()) {
485 morkRow* row = mRowObject_Row;
486 mRowObject_Row = 0;
487 this->CloseObject(ev);
488 this->MarkShut();
489
490 if (row) {
491 MORK_ASSERT(row->mRow_Object == this);
492 if (row->mRow_Object == this) {
493 row->mRow_Object = 0; // just nil this slot -- cut ref down below
494
495 mRowObject_Store = 0; // morkRowObjects don't ref-cnt the owning store.
496
497 this->CutWeakRef(
498 ev->AsMdbEnv()); // do last, because it might self destroy
499 }
500 }
501 } else
502 this->NonNodeError(ev);
503 }
504
505 // } ===== end morkNode methods =====
506 // ````` ````` ````` ````` `````
507
NonRowObjectTypeError(morkEnv * ev)508 /*static*/ void morkRowObject::NonRowObjectTypeError(morkEnv* ev) {
509 ev->NewError("non morkRowObject");
510 }
511
NilRowError(morkEnv * ev)512 /*static*/ void morkRowObject::NilRowError(morkEnv* ev) {
513 ev->NewError("nil mRowObject_Row");
514 }
515
NilStoreError(morkEnv * ev)516 /*static*/ void morkRowObject::NilStoreError(morkEnv* ev) {
517 ev->NewError("nil mRowObject_Store");
518 }
519
RowObjectRowNotSelfError(morkEnv * ev)520 /*static*/ void morkRowObject::RowObjectRowNotSelfError(morkEnv* ev) {
521 ev->NewError("mRowObject_Row->mRow_Object != self");
522 }
523
AcquireRowHandle(morkEnv * ev)524 nsIMdbRow* morkRowObject::AcquireRowHandle(morkEnv* ev) // mObject_Handle
525 {
526 AddRef();
527 return this;
528 }
529
530 // 456789_123456789_123456789_123456789_123456789_123456789_123456789_123456789
531