OOFILE  1.9
oofview.cpp
Go to the documentation of this file.
1 // COPYRIGHT 1994 A.D. Software, All rights reserved
2 
3 // public layer of OOFILE database - database views
4 
5 #include "oofpch_c.h" // for precompilation of core files
6 
7 #ifndef H_OOFIOS
8  #include "oofios.h"
9 #endif
10 #ifndef H_OOF4
11  #include "oof4.h"
12 #endif
13 #ifndef H_OOFREL
14  #include "oofrel.h"
15 #endif
16 #ifndef H_OOFVIEW
17  #include "oofview.h"
18 #endif
19 
20 #ifdef OOF_MEM_DEBUG_LAST_INCLUDE
21  #include OOF_MEM_DEBUG_LAST_INCLUDE
22 #endif
23 
24 #ifndef OOF_NO_STDLIB
25  #ifndef std
26  using namespace std;
27  #endif
28 #endif
29 
30 
31 // -------------------------------------------------------
32 // d b V i e w
33 // -------------------------------------------------------
34 
36  mTable(0),
37  mCloneSource(false),
38  mSuppressHeadings(false),
39  mSpecifiedFindFieldNum(USHRT_MAX)
40 {
41 }
42 
43 
44 dbView::dbView(dbTable* tbl, bool cloneSource) :
45  mCloneSource(cloneSource),
46  mSuppressHeadings(false),
47  mSpecifiedFindFieldNum(USHRT_MAX)
48 {
49  if (tbl) { // is now legal to have nil pointer, could be collection of standalone oofChars etc.
50  // so allow a nil dbTable* and will iterate ONCE
51  if (tbl->isRelatedClone()) {
52  cloneSource = false; // don't allow cloning of these related tables
53  mCloneSource = false;
54  }
55  if (cloneSource)
56  mTable = tbl->cloneTableSharingSelection();
57  else
58  mTable = tbl;
59  }
60  else
61  mCloneSource = false; // can't clone if have no table
62 }
63 
64 
65 dbView::dbView(dbTable& tbl, bool cloneSource) :
66  mCloneSource(cloneSource),
67  mSuppressHeadings(false),
68  mSpecifiedFindFieldNum(USHRT_MAX)
69 {
70  if (tbl.isRelatedClone()) {
71  cloneSource = false; // don't allow cloning of these related tables
72  mCloneSource = false;
73  }
74  if (cloneSource)
75  mTable = tbl.cloneTableSharingSelection();
76  else
77  mTable = &tbl;
78 }
79 
80 
81 dbView::dbView(dbRelRefBase* tblRef, bool cloneSource) :
82  mCloneSource(cloneSource),
83  mSuppressHeadings(false),
84  mSpecifiedFindFieldNum(USHRT_MAX)
85 {
86  if (tblRef) {
87  assert(!cloneSource); // don't support cloning related tables
88  mTable = tblRef->relatedTable();
89  }
90  else
91  mTable = 0;
92 }
93 
94 
95 dbView::dbView(dbRelRefBase& tblRef, bool cloneSource) :
96  mCloneSource(cloneSource),
97  mSuppressHeadings(false),
98  mSpecifiedFindFieldNum(USHRT_MAX)
99 {
100  assert(!cloneSource); // don't support cloning related tables
101  mTable = tblRef.relatedTable();
102 }
103 
104 
105 dbView::dbView(const dbView& rhs, bool keepIndependentSelection) :
106  OOF_Dictionary(rhs),
107  OOF_mixColSizable(rhs),
108  mTable(rhs.mTable),
109  mCloneSource(rhs.mCloneSource),
110  mHeadings(0, rhs.mHeadings.count()),
111  mOwnedFieldsInView(rhs.mOwnedFieldsInView),
112  mSuppressHeadings(rhs.mSuppressHeadings),
113  mSpecifiedFindFieldNum(rhs.mSpecifiedFindFieldNum)
114 {
115  if (keepIndependentSelection) { // explicit!
116  mCloneSource = true;
117  mTable = mTable->cloneTable(); // even if it's a related table
118  }
119  else {
120  if (mCloneSource) { // rhs had cloned source so we must too!
121  assert(mTable && !mTable->isRelatedClone());
122  mTable = mTable->cloneTableSharingSelection();
123  }
124  }
125  FinishCopy(rhs);
126 }
127 
128 
129 dbView::dbView(const dbView& rhs, dbTable* newTable) :
130  OOF_Dictionary(rhs),
131  OOF_mixColSizable(rhs),
132  mTable(newTable),
133  mCloneSource(false),
134  mHeadings(0, rhs.mHeadings.count()),
135  mOwnedFieldsInView(rhs.mOwnedFieldsInView),
136  mSuppressHeadings(rhs.mSuppressHeadings),
137  mSpecifiedFindFieldNum(rhs.mSpecifiedFindFieldNum)
138 {
139  assert(rhs.table()->tableNumber() == newTable->tableNumber());
140  FinishCopy(rhs); // still called to do rest of finishing
141 }
142 
143 
144 dbView*
145 dbView::clone(bool keepIndependentSelection) const
146 {
147  return new dbView(*this, keepIndependentSelection);
148 }
149 
150 
151 void
152 dbView::cloneTable(bool shareSelection)
153 {
154  if (mTable) {
155  dbTable* newTable;
156  if (shareSelection)
157  newTable = mTable->cloneTableSharingSelection();
158  else
159  newTable = mTable->cloneTable();
160  if (mCloneSource)
161  delete mTable;
162  mCloneSource = true;
163  mTable = newTable;
165  }
166 }
167 
168 
169 void
171 {
172  const unsigned long numFields = count();
173  OOF_DictRep* oldRep = mRep;
174  if(oldRep->mReferences>1) { // called from a copy
175  // so the rep has been used by us plus the copied rhs, at least
176  --(oldRep->mReferences); // decrement because we're not using that rep
177  mRep = new OOF_DictRep(numFields, 1 /*expansion size*/); // just alloc, don't copy
178  } // otherwise just update in place
179 
180  for (unsigned int fi=0; fi < numFields; fi++) {
181  const dbField* theField = (const dbField*) oldRep->value(fi); // safe downcast
182  mRep->item(fi) = theField->equivalentFieldFromTable(mTable); // correct field to point to clone
183  }
184 }
185 
186 
187 void
189 {
190  if (mTable!=rhs.mTable) {
191  assert(mTable); // a nil table pointer forces mCloneSource==false
192  // correct all the copied field pointers to point to our newly cloned table
194  }
195  const unsigned long numHeadings = rhs.mHeadings.count();
196  for (unsigned int i=0; i<numHeadings; i++) {
197  oofString* aHeading = (oofString*) rhs.mHeadings.value(i); // safe downcast
198  if (aHeading)
199  setHeading(i, *aHeading);
200  }
201 }
202 
203 
204 const dbView&
206 {
207  if (this == &rhs)
208  return *this;
209 
210  mTable = rhs.mTable;
211  return *this;
212 }
213 
214 
216 {
217  if (mCloneSource)
218  delete mTable;
219 // delete any headings allocated.
220 // Note that they may not have been allocated up to or past all the fields in the view
221  for (unsigned int i=0; i<mHeadings.count(); i++) {
222  unsigned long maybeHead = mHeadings.value(i);
223  if (maybeHead)
224  delete (oofString*) maybeHead;
225  }
226 // delete any owned fields
227  if (mRep->mReferences<=1) {
228  const unsigned int numOwned = mOwnedFieldsInView.count();
229  for (unsigned int j=0; j<numOwned; j++) {
230  const unsigned long fieldInView = mOwnedFieldsInView.value(j);
231  OOF_bitPointer ownedField = value(fieldInView);
232  delete ownedField;
233  }
234  }
235 }
236 
237 
238 oofString
240 {
241  if (mOverrideName.isEmpty()) {
242  if (mTable)
243  return mTable->tableName();
244  else
245  return oofString();
246  }
247  else
248  return mOverrideName;
249 }
250 
251 
252 const dbField&
254 {
255 // may return a field not in the view, if sort order by a non-visible field
256  fieldNumT theFieldNum = 0; // all other cases default to first field in view
257  if (mSpecifiedFindFieldNum != USHRT_MAX) {
258  theFieldNum = mSpecifiedFindFieldNum;
259  }
260  else {
261  if (mTable) {
262  const dbSorter* tableSorter = mTable->sorter();
263  if (tableSorter) {
264  const fieldNumT sortFieldNum = tableSorter->sortFieldNo();
265  dbField* sortField = mTable->field(sortFieldNum);
266  assert(sortField);
267  return *sortField; // RETURN SORT FIELD, NOT NECESSARILY IN VIEW
268  }
269  }
270  }
271  const dbField* ret = (const dbField*) value(theFieldNum); // safe downcast
272  assert(ret);
273  return *ret;
274 }
275 
276 
277 oofString
278 dbView::getHeading(unsigned int fieldNoInView, bool* tellIfOverride) const
279 {
280  const oofString* maybeHead = (const oofString*)mHeadings.value(fieldNoInView);
281  oofString ret;
282  if (tellIfOverride)
283  *tellIfOverride = (maybeHead!=0);
284  if (maybeHead)
285  ret = *maybeHead; // safe downcast
286  else
287  ret = field(fieldNoInView).fieldName();
288  ret.replaceChar('_', ' ');
289  return ret;
290 }
291 
292 
293 oofString
295 {
296 // NOTE repeat the entire getHeading to avoid extra return object copies
297 // that we'd get by calling getHeading from here
298 // unless the compiler's optimizer is *very* good about optimising temp objects
299  const unsigned long maybeHead = mHeadings.value(mInternalIter);
300  if (maybeHead)
301  return *( (const oofString*)maybeHead);
302  else
303  return field(mInternalIter).fieldName();
304 }
305 
306 
307 void
308 dbView::setHeading(unsigned int fieldNoInView, const char* inHead)
309 {
310  const unsigned long maybeHead = mHeadings.value(fieldNoInView);
311  oofString* theHead;
312  if (maybeHead) {
313  theHead = (oofString*) maybeHead; // safe downcast - this class owns the list
314  *theHead = inHead; // change content of oofString object - it's already in the list
315  }
316  else {
317  theHead = new oofString(inHead);
318  assert(sizeof(unsigned long)==sizeof(oofString*)); // we make this sort of assumption a lot!
319  mHeadings[fieldNoInView] = (unsigned long) theHead; // adopt the string
320  }
321 }
322 
323 
327 dbView&
329 {
330  if (rhs.fieldIsStandalone()) {
331  dbField* newField = rhs.clone(); // copy refs as probably local temp variables
332  AppendOwnedField(newField);
333  }
334  else {
335  append((dbField*) &rhs); // const_cast, safe as we don't delete our fields
336  }
337  return *this;
338 }
339 
340 
350 dbView&
352 {
353  if (rhs->fieldIsStandalone()) {
354  AppendOwnedField(rhs); // adopt pointers as expect inline 'new dbChar' expressions
355  }
356  else {
357  bool useEquivField;
358  if (mCloneSource) // our table is guaranteed not to be same as theirs
359  useEquivField = true;
360  else { // see if rhs is just on a clone of our table
361  dbTable* rhsTable = rhs->fieldTable();
362  useEquivField = (rhsTable!=mTable && rhsTable->tableNumber()==mTable->tableNumber());
363  }
364  if (useEquivField)
366  else
367  OOF_Dictionary::append(rhs); // field could be related, could be totally unrelated, don't care
368  }
369  return *this;
370 }
371 
372 
376 dbView&
378 {
379  assert (!rhs->fieldIsStandalone());
380  append((dbField*) rhs); // const_cast, safe as we don't delete our fields
381  return *this;
382 }
383 
384 
385 dbView&
386 dbView::append(const char* rhs)
387 {
388  oofChar* newField = new oofChar(rhs);
389  AppendOwnedField(newField);
390  return *this;
391 }
392 
393 
394 
395 void
397 {
398  const unsigned long ownedFieldIndex = count();
399  mOwnedFieldsInView.append(ownedFieldIndex);
400  if (adoptedField->fieldName().length()==0) {
401  char buf[15];
402  sprintf(buf, "field%lu", ownedFieldIndex);
403  adoptedField->setName(buf);
404  }
405  OOF_Dictionary::append(adoptedField);
406 }
407 
408 
409 ostream&
410 operator<<(ostream& os, dbView& theView)
411 {
412  theView.extract(os);
413  return os;
414 }
415 
416 
417 void
418 dbView::extract(ostream& os)
419 {
420  unsigned long numRecs = 1; // default is to iterate once with nil pointer
421  if (mTable) {
422  mTable->start(); // this precedes count() as a bit of a hack from the past, to force table validity
423  numRecs = mTable->count();
424  }
425  const unsigned int numFields = count();
426  // print a row of headings
427  bool printedAny = false;
428  for (unsigned int col=0; col<numFields; col++) { // print headings
429  oofString head = getHeading(col);
430  if (head.length())
431  printedAny = true;
432  os << head << '\t';
433  }
434  os << endl; // which may be after empty line of tabs
435  if (printedAny) {
436  for (unsigned int col=0; col<numFields; col++) { // print underlines for headings
437  const unsigned long headLen = getHeading(col).length();
438  os << oofString('-',headLen) << '\t';
439  }
440  os << endl;
441  }
442  for (unsigned long row=0; row<numRecs; row++) { // iterate through records (vertical)
443  for (unsigned int col=0; col<numFields; col++) { // start field iteration (horizontal)
444  field(col).extract(os);
445  os << '\t';
446  }
447  os << endl;
448  if (mTable && row<numRecs-1)
449  mTable->next();
450  }
451 }
452 
453 
455 dbView::MakeDefaultSizer(unsigned int /*numCols*/) const
456 {
457  return new oofViewFieldDefaultsColSizer(this);
458 }
459 
460 
virtual dbTable * cloneTable(selSharingT selSharing=selCopyOnWrite)=0
oofString currentHeading() const
Definition: oofview.cpp:294
unsigned long count()
Count records in current selection.
Definition: oof1.h:2017
virtual const oofString & fieldName() const
Definition: oof3.h:769
precompilation header.
const dbField & defaultFindField() const
Definition: oofview.cpp:253
tableNumT tableNumber() const
Definition: oof1.h:2376
dbField * equivalentFieldFromTable(dbTable *) const
Definition: oof3.cpp:352
virtual oofColSizer * MakeDefaultSizer(unsigned int numCols=0) const
Definition: oofview.cpp:455
Tries to hide the different platforms and version issues with standard IO.
Base class for something which can have column widths specified.
Definition: oofsize.h:23
bool fieldIsStandalone() const
Definition: oof3.h:733
dbTable * relatedTable()
Definition: oofrel.cpp:1074
void start()
Definition: oof1.cpp:2057
unsigned long count() const
Definition: oofarray.h:126
const dbField & field(unsigned int) const
Definition: oofview.h:206
void FinishCopy(const dbView &rhs)
Definition: oofview.cpp:188
void append(OOF_bitPointer)
Definition: oof1.h:1551
dbView()
Definition: oofview.cpp:35
void setName(const char *name)
Definition: oof3.cpp:195
OOF_bitPointer value(unsigned int index) const
Definition: oof1.h:1594
const dbView & operator=(const dbView &)
Definition: oofview.cpp:205
Specify or calculate a set of column widths & alignments.
Definition: oofsize.h:51
Calculate a set of column widths from field types in a view.
Definition: oofsize.h:94
Parent for any field that is a relationship to another table.
Definition: oofrel.h:19
bool isRelatedClone() const
Definition: oof1.h:2348
Provide an iterable set of fields.
Definition: oofview.h:26
dbView & append(const dbField &)
Append field to view, cloning standalone fields or using append(dbField*).
Definition: oofview.cpp:328
bool isEmpty() const
Test based on either length or null pointer.
Definition: oofstr.h:413
unsigned long length() const
Primary test: oofStringTest::emptyStringByNullInitIsLenZero()
Definition: oofstr.h:447
void cloneTable(bool shareSelection=false)
Definition: oofview.cpp:152
unsigned int mReferences
Definition: oof1.h:90
void setHeading(unsigned int, const char *)
Definition: oofview.cpp:308
unsigned long replaceChar(char fromChar, char toChar, unsigned long startAt=0)
Definition: oofstr.cpp:963
const oofString & tableName() const
Definition: oof1.h:2369
Specify sort order by one more fields.
Definition: oof1.h:1277
OOF_DictRep * mRep
Definition: oof1.h:213
virtual dbTable * cloneTableSharingSelection() const
Definition: oof1.cpp:1433
Base class used to refer to main OOFILE classes and provide base reflective API.
Definition: oof1.h:49
void AppendOwnedField(dbField *adoptedField)
Definition: oofview.cpp:396
~dbView()
Definition: oofview.cpp:215
OOF_Dictionary clone() const
Definition: oof2.cpp:389
dbField * field(fieldNumT) const
Definition: oof1.h:2355
unsigned int count() const
Definition: oof1.h:1498
unsigned short fieldNumT
Definition: oof1.h:276
Base class for persistent tables.
Definition: oof1.h:452
virtual void extract(std::ostream &) const
Definition: oof3.cpp:506
void AdjustFieldsToNewTable()
Definition: oofview.cpp:170
dbTable * fieldTable() const
Definition: oof3.cpp:308
void next()
Next record in the selection becomes current.
Definition: oof1.h:1970
Portable highly capable string class.
Definition: oofstr.h:101
void append(unsigned long)
Definition: oofarray.cpp:131
oofString name() const
Definition: oofview.cpp:239
virtual dbField * clone() const =0
virtual unsigned short sortFieldNo() const
Definition: oof1.cpp:3038
void extract(std::ostream &)
Definition: oofview.cpp:418
std::ostream & operator<<(std::ostream &, const oofE_Base &)
Representation of ref-counted dictionary.
Definition: oof1.h:121
dbSorter * sorter() const
Definition: oof1.h:2415
dbTable * table() const
Definition: oofview.h:109
unsigned int mInternalIter
Definition: oof1.h:214
Use to have local non-persistent variable of type dbChar.
Definition: oof4.h:1126
Base class for persistent fields in dbTable's.
Definition: oof3.h:63
unsigned long value(unsigned long index) const
Definition: oofarray.cpp:243
Provides searchable dictionary of common OOFILE classes like dbTable.
Definition: oof1.h:159
oofString getHeading(unsigned int, bool *tellIfOverride=0) const
Definition: oofview.cpp:278