OOFILE  1.9
oofpphier.cpp
Go to the documentation of this file.
1 // COPYRIGHT 1996 A.D. Software, All rights reserved
2 
3 // PowerPlant Integration layer of OOFILE database
4 #include "oofpphier.h"
5 #ifndef H_OOFPowerPlantX
6  #include "oofppx.h" // private interface, includes public
7 #endif
8 #ifndef H_OOF2
9  #include "oof2.h"
10 #endif
11 #ifndef H_OOF4
12  #include "oof4.h"
13 #endif
14 #ifndef H_OOFVIEW
15  #include "oofview.h"
16 #endif
17 #ifndef H_OOFREL
18  #include "oofrel.h"
19 #endif
20 #ifndef H_OOFQUERY
21  #include "oofquery.h"
22 #endif
23 #ifndef H_stSetCursor
24  #include "stSetCursor.h"
25 #endif
26 
27 // include PowerPlant definitions
28 #include <LEditField.h>
29 #include <LCaption.h>
30 #include <LListBox.h>
31 #include <UMemoryMgr.h>
32 #include <PP_Messages.h>
33 #include <LOutlineTable.h>
34 
35 
36 // -------------------------------------------------------
37 // d b V i e w O u t l i n e I t e m
38 //-------------------------------------------------------
39 
40 dbViewOutlineItem::dbViewOutlineItem(oidT inOID, dbHierBrowseHelper* inHelper, unsigned short indentLevel, bool isLeaf) :
41  OOF_mixOutlineItem(inOID, inHelper, indentLevel, isLeaf)
42 {
43 }
44 
45 
47 {
48 }
49 
50 
51 Boolean
53 {
54  const bool ret = !isLeaf();
55  return ret;
56 }
57 
58 
59 void
61 {
62  mHelper->insertItemsBelow(this, this); // pass twice, as LOutlineItem and OOF_mixOutlineItem
63 }
64 
65 
66 void
68  const STableCell& inCell,
69  SOutlineDrawContents& ioDrawContents)
70 {
71  GetDrawContentsFromView(inCell, ioDrawContents);
72 }
73 
74 
75 
76 void
78  const STableCell& inCell,
79  const SMouseDownEvent& inMouseDown)
80 {
81 // COPIED FROM LOutlineItem & changed to use the table's selector to decide what kind of
82 // selection we get
83 
84  // Find out what we're supposed to draw.
85 
86  SOutlineDrawContents drawInfo;
87  GetDrawContents(inCell, drawInfo);
88 
89  // Test disclosure triangle for first column.
90 
91  if ((inCell.col == 1) && CanExpand()) {
92  Rect disclosureFrame;
93  CalcLocalDisclosureTriangleRect(disclosureFrame);
94  if (::PtInRect(inMouseDown.whereLocal, &disclosureFrame)) {
95  TrackDisclosureTriangle(inMouseDown);
96  return;
97  }
98  }
99 
100  // If there's an icon, hit test it.
101  if (drawInfo.outHasIcon && (drawInfo.outIconSuite != nil)) {
102  if (::PtInIconSuite(inMouseDown.whereLocal, &drawInfo.prIconFrame, drawInfo.outIconAlign, drawInfo.outIconSuite)) {
103  TrackContentClick(inCell, inMouseDown, drawInfo, false);
104  return;
105  }
106  }
107  mOutlineTable->GetTableSelector()->ClickSelect(inCell, inMouseDown);
108 }
109 
110 
111 // -------------------------------------------------------
112 // O O F _ m i x O u t l i n e I t e m
113 // -------------------------------------------------------
114 OOF_mixOutlineItem::OOF_mixOutlineItem(oidT inOID, dbHierBrowseHelper* inHelper, unsigned short indentLevel, bool isLeaf) :
115  mOID(inOID),
116  mHelper(inHelper),
117  mIndentLevel(indentLevel),
118  mCacheIndex(inHelper->nextCacheIndex()),
119  mIsLeaf(isLeaf)
120 {}
121 
122 
123 dbView*
125 {
126  return mHelper->viewAtLevel(mIndentLevel);
127 }
128 
129 
132 {
133  return mHelper->level(mIndentLevel);
134 }
135 
136 
137 bool
139 {
140 // Flyweight pattern at work here!
141  dbView* theView = view();
142  dbTable* theTable = theView->table();
143  bool ret;
144  if (theTable)
145  ret = theTable->selectJustOID(mOID);
146  else
147  ret = false;
148  return ret;
149 }
150 
151 
152 void
153 OOF_mixOutlineItem::GetDrawContentsFromView(const STableCell& inCell, SOutlineDrawContents& ioDrawContents)
154 {
155  const fieldNumT fieldNum = inCell.col-1; // 1-based
156  dbView* theView = view();
157  const unsigned short numFields = theView->count();
158  if (fieldNum>=numFields)
159  return; // early exit for more columns than we have in this view
160 
161  const char* contents = mHelper->getCachedContents(mCacheIndex, fieldNum);
162  if (!contents) { // assume entire row not cached
163  dbTable* theTable = theView->table();
164  stSaveSelection saveTable(theTable);
165  theTable->selectJustOID(mOID);
166 // now iterate across the fields and copy all values into the cache
167  mHelper->initCacheRow(mCacheIndex, numFields);
168  for (unsigned short i=0; i<numFields; i++) {
169  const dbField& theField = theView->field(i);
170  assert(
171  !theField.fieldTable() || // standalone fields OK
172  !theView->table() || // view without table iterates once, might have fields from anywhere
173  theField.fieldTable()==theView->table() || // field should be on view's table, if both have tables
174  theField.fieldTable()->baseTableOfRelationChain()==theView->table() // or be on related table
175  );
176  oofString fieldContents = theField.copyString();
177  mHelper->setCachedContents(mCacheIndex, i, fieldContents.orphan());
178  }
179  contents = mHelper->getCachedContents(mCacheIndex, fieldNum);
180  assert(contents); // we just put them there!
181  }
182 // copy contents to return string
183  unsigned long contentLen = strlen(contents);
184  if (contentLen>255)
185  contentLen = 255; // restrict to Pascal string
186  memcpy(&ioDrawContents.outTextString[1], contents, contentLen);
187  ioDrawContents.outTextString[0] = contentLen;
188  ioDrawContents.outShowSelection = true;
189 }
190 
191 
192 oidT
193 OOF_mixOutlineItem::findOIDforData(const void* inDataPtr, UInt32 inDataSize) const
194 {
195 // sole use to-date is CDragDropOutlineTable::FindCellData where it is used
196 // to locate a visible cell matching the user's typing
197 
198  oidT ret = 0;
199  dbView* theView = view();
200  dbTable* viewTable = theView->table();
201  if (viewTable) { // legal to have views with no table - they behave as if 1 record
202  if (inDataSize) {
203  assert(inDataPtr);
204  const dbField* searchField = &theView->defaultFindField();
205  dbQueryLiteral* rhsLiteral = 0;
206  dbQueryField* lhsField = new dbQueryField(searchField);
207  assert(lhsField);
208  if (searchField->fieldType() == charField || searchField->fieldType() == compoundField) {
209  OOF_String rhsString((const char*)inDataPtr, inDataSize);
210  rhsLiteral = new dbQueryLiteralStr(rhsString);
211  dbQueryClause* theSearch = new dbQueryBinary(
212  lhsField,
213  dbQueryClause::greaterThanOrEqual, /* want to get next cell after if no match */
214  rhsLiteral
215  );
216  stSaveSelection saveView(viewTable);
217  viewTable->search(theSearch); // in hier tables, always destroying the context
218  viewTable->start(); // goto the first found record
219  ret = viewTable->currentOID();
220  delete theSearch;
221  } // is a char field
222  // NOT YET IMPLEMENTED - cope with others, see CQueryEngine::performSearch
223  } // have data to find
224  }
225  return ret;
226 }
227 
228 
229 // -------------------------------------------------------
230 // d b H i e r B r o w s e H e l p e r
231 // -------------------------------------------------------
232 dbHierBrowseHelper::dbHierBrowseHelper(LOutlineTable* inTable) :
234  mOutlineTable(inTable),
235  mNextCacheIndex(0),
236  mContentsCache(0)
237 {
238 }
239 
240 
242 {
243  mOutlineTable = 0; // so don't try to update it in the following
244  deleteAllLevels();
245 }
246 
247 
248 void
250 {
251  if(mOutlineTable) {
252  dbView* topView = viewAtLevel(0);
253  const unsigned short numCols = 1 + topView->count(); // 1 for disclosure triangle
254 
255 // delete all the items in our associated Outline Table
256  const LArray& firstLevelItems = mOutlineTable->GetFirstLevelItems();
257  UInt32 numItems = firstLevelItems.GetCount();
258  if (numItems) {
259  LOutlineItem* item;
260  while (numItems>1) {
261  firstLevelItems.FetchItemAt(numItems, &item); // 1-based arrays
262  mOutlineTable->RemoveItem(item, false /* no refresh */, false /*don't adjust image size*/);
263  numItems--;
264  } // loop to remove all bar first item
265  firstLevelItems.FetchItemAt(1, &item); // 1-based arrays
266  mOutlineTable->RemoveItem(item, false /* no refresh */, true /* FINALLY adjust image size*/);
267  }
268 // now quickly remove the cols to make sure LSelector's etc. are updated
269  mOutlineTable->RemoveCols(numCols, 1, false /* don't refresh */);
270  } // delete outline table's stuff
271 
272 // delete our level info
273  const unsigned short numLevels = mHierLevels.count();
274  for (unsigned short i=0; i<numLevels; i++) {
275  dbHierLevel* toDel = level(i);
276  delete toDel;
277  }
278  mHierLevels = 0;
280 }
281 
282 
283 void
285 {
286 // largely a copy of browseViewWithTable
287 
288  assert(mHierLevels.count()); // should have set our levels first
289 
290  dbView* topView = viewAtLevel(0);
291  const unsigned short numCols = topView->count();
292  mOutlineTable->InsertCols(numCols, 0, 0, 0, 0);
293  const short kTriangleColWidth = 16; // hardcode triangle col
294 
295 // set col widths after loading establishes number of columns
296  SDimension16 tableSize;
297  mOutlineTable->GetFrameSize(tableSize);
298  oofColSizer* sizer = topView->colSizer();
299  sizer->calculateWidths(tableSize.width-kTriangleColWidth); // divides up widths according to field defaults or user rules
300 
301  const unsigned long firstDataColWidth = sizer->width(0) + kTriangleColWidth;
302  mOutlineTable->SetColWidth(firstDataColWidth, 1, 1);
303  for (unsigned short colFld=1; colFld<numCols; colFld++) { // assign remaining col widths
304  const unsigned long dataColWidth = sizer->width(colFld);
305  const unsigned short oneBasedCol = colFld+1;
306  mOutlineTable->SetColWidth(dataColWidth, oneBasedCol, oneBasedCol); // from, to col No's
307  }
308 
309 // need to set cols before the table is displayed,
310 // but has no effect on the following
311  insertItemsBelow(0, 0); // add all the top-level items
312 }
313 
314 
315 void
317 {
319  if (mOutlineTable)
320  mOutlineTable->Refresh();
321 }
322 
323 
324 unsigned long
326 {
327  unsigned long ret = mNextCacheIndex;
328  mNextCacheIndex++;
329  return ret;
330 }
331 
332 
333 
334 void
336 {
337  const unsigned long numRows = mContentsCache.count();
338  for (unsigned long i=0; i<numRows; i++) {
339  char** contentsRow = (char**) mContentsCache.value(i);
340  if (contentsRow) {
341  for (unsigned short j=0; contentsRow[j]; j++) {
342  char* aString = contentsRow[j];
343  delete[] aString;
344  }
345  }
346  delete[] contentsRow;
347  mContentsCache[i] = 0;
348  }
350  mNextCacheIndex = 0;
351 }
352 
353 
354 void
355 dbHierBrowseHelper::initCacheRow(unsigned long cacheIndex, fieldNumT numFields)
356 {
357  char** contentsRow = (char**) mContentsCache.value(cacheIndex); // may be existing
358  if (contentsRow==0) {
359  contentsRow = new char*[numFields+1];
360  for (unsigned short i=0; i<=numFields; i++) // YES I MEAN <=numFields
361  contentsRow[i] = 0;
362  mContentsCache[cacheIndex] = (unsigned long) contentsRow;
363  }
364 }
365 
366 
367 const char*
368 dbHierBrowseHelper::getCachedContents(unsigned long cacheIndex, fieldNumT fieldNum)
369 {
370  char** contentsRow = (char**) mContentsCache.value(cacheIndex);
371  const char* ret = 0;
372  if (contentsRow)
373  ret = contentsRow[fieldNum];
374  return ret;
375 }
376 
377 
378 void
379 dbHierBrowseHelper::setCachedContents(unsigned long cacheIndex, fieldNumT fieldNum, char* adoptedStr)
380 {
381  char** contentsRow = (char**) mContentsCache.value(cacheIndex);
382  assert(contentsRow);
383  char* existingContent = contentsRow[fieldNum] ;
384  delete[] existingContent;
385  contentsRow[fieldNum] = adoptedStr;
386 }
387 
388 
389 void dbHierBrowseHelper::browseViewWithTable(LOutlineTable* inTable)
390 {
391  mOutlineTable = inTable;
393 }
394 
395 
396 void
398 {
399  if (mHierLevels.count()==0) {
400  dbView* topView = adoptedLevel->view();
401  if (topView) {
402  dbTable* topTable = topView->table();
403  if (topTable) {
404  dbGUI* ourGUI = topTable->getGUI();
405  subscribeTo(ourGUI);
406  }
407  }
408  }
409  mHierLevels.append((unsigned long)adoptedLevel);
410 }
411 
412 
413 unsigned long
414 dbHierBrowseHelper::countNestedItemsFromLevel(oidT inOID, unsigned short inLevel) const
415 {
416  dbHierLevel* theLevel = level(inLevel);
417  assert(theLevel);
418  unsigned long ret = theLevel->countNestedItemsFor(inOID);
419  return ret;
420 }
421 
422 
423 dbView*
424 dbHierBrowseHelper::viewAtLevel(unsigned short inLevel) const
425 {
426  dbHierLevel* theLevel = level(inLevel);
427  assert(theLevel);
428  dbView* ret = theLevel->view();
429  return ret;
430 }
431 
432 
433 void
435 {
436  stSetCursor displayWatchByDefault; // bit of user feedback so they know it's OK if it takes a while
437 
438 // used to initially set the contents of the LOutlineTable
439  dbSelection* savedTopSelection=0;
440  dbTable* addingTable;
441  dbTable* superTable = 0;
442  dbHierLevel* superLevel;
443  unsigned short nestedIndentLevel = 0;
444  if (inSuperDataManager) {
445  superLevel = inSuperDataManager->level();
446  assert(superLevel);
447  superTable = superLevel->view()->table();
448  savedTopSelection = new dbSelection(superTable->currentSelection());
449  addingTable = superLevel->selectNestedItemsFor(inSuperDataManager->oid());
450  nestedIndentLevel = inSuperDataManager->indentLevel()+1;
451  }
452  else {
453  dbView* topView = viewAtLevel(0);
454  addingTable = topView->table();
455  superLevel = level(0);
456  }
457 
458  if (addingTable) { // records below specific outline item
459  if (nestedIndentLevel>deepestIndent()) { // assume recursive situation, need to make a level
460  dbHierLevel* nestedLevel = superLevel->makeNestedLevel(); // may be zero if non-recursive levels
461  assert(nestedLevel); // assert our levels are capable of extending themselves
462  appendLevel(nestedLevel);
463  }
464  LOutlineItem* prevItem = 0;
465  const unsigned short numToInsert = addingTable->count();
466  addingTable->start();
467  for (unsigned short i=0; i<numToInsert; i++) {
468  const oidT theOID = addingTable->currentOID();
469  LOutlineItem* theItem = superLevel->makeNestedOutlineItem(theOID, this, nestedIndentLevel);
470  mOutlineTable->InsertItem(theItem, inSuper, prevItem);
471  prevItem = theItem;
472  addingTable->next();
473  } // add loop
474  } // bottom of hierarchy
475 
476  if (savedTopSelection && superTable) {
477  superTable->setSelection(*savedTopSelection);
478  delete savedTopSelection;
479  }
480 }
481 
482 
483 oidT
485 {
486 // much more efficient than highlightedSelection if we just want one record
487 // make it return the OID of the FIRST record selected, even if multiple selected
488 
489 // works a little differently to the dbBrowser version because we deal with views that
490 // (for now) are assumed to be at different levels of a file.
491 // thus, higher levels are translated into a set of the bottom-most view's records
492 // BUT we only need to take this process far enough to get one OID
493 
494  assert(mHierLevels.count());
495  dbTable* tbl = lowestLevel()->view()->table();
496  oidT ret = 0;
497 
498  TableIndexT lastRow = 0;
499 // still do iteration as may have higher levels selected that lack a lower level
500 // equivalent to a Finder selection that starts with several empty folders,
501 // and we want the first file in a depth-first traversal
502  for (STableCell selCell = mOutlineTable->GetFirstSelectedCell();
503  !selCell.IsNullCell();
504  mOutlineTable->GetNextSelectedCell(selCell)
505  )
506  {
507  if (selCell.row==lastRow)
508  continue; // skip cells on same row
509 
510 #ifndef OOF_RTTI_ENABLED
511  #pragma error "OOFILE GUI requires RTTI
512 #endif
513  OOF_mixOutlineItem* theItem = dynamic_cast<OOF_mixOutlineItem*>(mOutlineTable->FindItemForRow(selCell.row));
514  if (theItem && theItem->isLeaf()) {
515  ret = theItem->oid(); // just one row added
516  break; // GOT ONE!
517  }
518  else { // selected further up tree - propagate to lowest level
519  ret = FirstOIDBelowItem(theItem->indentLevel(), theItem->oid());
520  }
521  lastRow = selCell.row;
522  }
523  return ret;
524 }
525 
526 
529 {
530 
531 // works a little differently to the dbBrowser version because we deal with views that
532 // (for now) are assumed to be at different levels of a file.
533 // thus, higher levels are translated into a set of the bottom-most view's records
534 
535  assert(mHierLevels.count());
536  dbTable* tbl = lowestLevel()->view()->table();
537  dbSelection ret = tbl->makeEmptySelection();
538 
539  TableIndexT lastRow = 0;
540  for (STableCell selCell = mOutlineTable->GetFirstSelectedCell();
541  !selCell.IsNullCell();
542  mOutlineTable->GetNextSelectedCell(selCell)
543  )
544  {
545  if (selCell.row==lastRow)
546  continue; // skip cells on same row
547 
548 #ifndef OOF_RTTI_ENABLED
549  #pragma error "OOFILE GUI requires RTTI
550 #endif
551  OOF_mixOutlineItem* theItem = dynamic_cast<OOF_mixOutlineItem*>(mOutlineTable->FindItemForRow(selCell.row));
552  if (theItem && theItem->isLeaf()) {
553  ret += theItem->oid(); // just one row added
554  }
555  else { // selected further up tree - propagate to lowest level
556  IncludeAllBelowItem(theItem->indentLevel(), theItem->oid(), ret);
557  }
558  lastRow = selCell.row;
559  }
560  return ret;
561 }
562 
563 
564 void
565 dbHierBrowseHelper::IncludeAllBelowItem(unsigned short inIndentLevel, oidT inOID, dbSelection& addTo) const
566 {
567  dbHierLevel* superLevel = level(inIndentLevel);
568  assert(superLevel);
569  stSaveSelection saveSuper(superLevel->view()->table()); // before selectNestedItemsFor() selects single OID out of selection
570  dbTable* nestedTable = superLevel->selectNestedItemsFor(inOID);
571  assert (nestedTable); // shouldn't be called on the last level
572 
573  unsigned short nestedIndentLevel = inIndentLevel+1;
574  const bool nestedLevelIsLowest = ( nestedIndentLevel==deepestIndent() );
575 
576  unsigned short numToInsert = nestedTable->count();
577  nestedTable->start();
578  for (unsigned short i=0; i<numToInsert; i++) {
579  oidT theOID = nestedTable->currentOID();
580  if (nestedLevelIsLowest) {
581  addTo += theOID; // just one row added
582  }
583  else { // selected further up tree - propagate to lowest level
584  // BUT can't assume is twisted open at this level, therefore need to iterate down the
585  // related table, NOT using items
586  IncludeAllBelowItem(nestedIndentLevel, theOID, addTo);
587  }
588  nestedTable->next();
589  }
590 }
591 
592 
593 oidT
594 dbHierBrowseHelper::FirstOIDBelowItem(unsigned short inIndentLevel, oidT inOID) const
595 {
596 // nearly straight copy of IncludeAllBelowItem but just return one OID rather than
597 // assembling a selection
598  dbHierLevel* superLevel = level(inIndentLevel);
599  assert(superLevel);
600  stSaveSelection saveSuper(superLevel->view()->table()); // before selectNestedItemsFor() selects single OID out of selection
601  dbTable* nestedTable = superLevel->selectNestedItemsFor(inOID);
602  assert (nestedTable); // shouldn't be called on the last level
603  oidT ret = 0;
604  unsigned short nestedIndentLevel = inIndentLevel+1;
605  const bool nestedLevelIsLowest = ( nestedIndentLevel==deepestIndent() );
606 
607  unsigned short numToInsert = nestedTable->count();
608  nestedTable->start();
609  for (unsigned short i=0; i<numToInsert; i++) {
610  oidT theOID = nestedTable->currentOID();
611  if (nestedLevelIsLowest) {
612  ret = theOID; // GOT IT
613  break;
614  }
615  else { // selected further up tree - propagate to lowest level
616  // BUT can't assume is twisted open at this level, therefore need to iterate down the
617  // related table, NOT using items
618  ret = FirstOIDBelowItem(nestedIndentLevel, theOID);
619  }
620  nestedTable->next();
621  }
622  return ret;
623 }
624 
625 
628 {
629  OOF_mixOutlineItem* ret = 0;
630  // caller assumes single selection
631  for (STableCell selCell = mOutlineTable->GetFirstSelectedCell();
632  !selCell.IsNullCell();
633  mOutlineTable->GetNextSelectedCell(selCell)
634  )
635  {
636 #ifndef OOF_RTTI_ENABLED
637  #pragma error "OOFILE GUI requires RTTI
638 #endif
639  ret = dynamic_cast<OOF_mixOutlineItem*>(mOutlineTable->FindItemForRow(selCell.row));
640  assert(ret); // assume it's one of ours!
641  return ret; // EXIT LOOP EARLY, SO JUST FIND SINGLE ITEM
642  }
643  return ret;
644 }
645 
646 
647 bool
649 {
650  bool ret = false;
651  OOF_mixOutlineItem* theItem = highlightedItem();
652  if (theItem) {
653  ret = theItem->selectItemRecord();
654  }
655  return ret;
656 }
657 
658 
659 unsigned long
661 {
662  return 0; // NOT YET IMPLEMENTED
663 }
664 
665 
666 
667 void
669 {
670  // NOT YET IMPLEMENTED
671 }
672 
673 
674 
675 void
676 dbHierBrowseHelper::highlightRecNo(unsigned long, bool bSelect) const
677 {
678  // NOT YET IMPLEMENTED
679 }
680 
681 
682 
683 void
685 {
686  // NOT YET IMPLEMENTED
687 }
688 
689 
690 dbView*
692 {
693  return viewAtLevel(0);
694 }
695 
696 
697 bool
698 dbHierBrowseHelper::receiveMsg(OOFmsgT msg, unsigned long senderDefined)
699 {
700  bool ret;
701  switch (msg) {
703  ret = (mOutlineTable==(void*)senderDefined);
704  break;
705 
706  default :
707  ret = dbAbstractBrowseHelper::receiveMsg(msg, senderDefined);
708  };
709  return ret;
710 }
711 
712 
713 // -------------------------------------------------------
714 // O O F _ m i x O u t l i n e I t e m F a c t o r y
715 // -------------------------------------------------------
716 LOutlineItem*
717 OOF_mixOutlineItemFactory::makeItem(oidT inOID, dbHierBrowseHelper* inHelper, unsigned short indentLevel)
718 {
719 // default factory
720 // assumes leaves only at bottom level
721 // makes dbViewOutlineItems
722 
723  const bool isLeaf = (indentLevel==inHelper->deepestIndent());
724  LOutlineItem* ret = new dbViewOutlineItem(inOID, inHelper, indentLevel, isLeaf);
725  return ret;
726 }
727 
728 
729 // -------------------------------------------------------
730 // d b V i e w O u t l i n e I t e m F a c t o r y
731 // -------------------------------------------------------
733  mLeafFieldNum(leafFieldNum),
734  mLastIndentLevel(0),
735  mLastLeafField(0)
736 {}
737 
738 
740  mLeafFieldNum(leafField.fieldNumber()),
741  mLastIndentLevel(0),
742  mLastLeafField(0)
743 {}
744 
745 
746 bool
747 dbOutlineItemFactory::IsLeaf(dbHierBrowseHelper* inHelper, unsigned short indentLevel)
748 {
749 // nice bit of caching avoids lookups of the actual field being checked whilst we are working
750 // at the same level. This speeds up item creation when multiple items created twisting open a level above
751 // which is the most common circumstance
752  if (!mLastLeafField || mLastIndentLevel!=indentLevel) { // cached values for different level or never set
753  dbTable* levelTable = inHelper->viewAtLevel(indentLevel)->table(); // assumes views not reset EVER whilst this object exists
754  mLastLeafField = (dbBool*) levelTable->field(mLeafFieldNum); // safe downcast verified below
755  assert(mLastLeafField->fieldType()==boolField);
756  // note that this field may not be in the visible view, and probably isn't!
757  mLastIndentLevel=indentLevel;
758  }
759  const bool ret = mLastLeafField->value();
760  return ret;
761 }
762 
763 
764 LOutlineItem*
765 dbOutlineItemFactory::makeItem(oidT inOID, dbHierBrowseHelper* inHelper, unsigned short indentLevel)
766 {
767 // default factory typically used in recursive trees
768 // works out if leaf based on a given field, at the current record of this level
769 // makes dbViewOutlineItems but subclass and just override this to make your own types
770  const bool itemIsLeaf = IsLeaf(inHelper, indentLevel);
771  LOutlineItem* ret = new dbViewOutlineItem(inOID, inHelper, indentLevel, itemIsLeaf);
772  return ret;
773 }
774 
775 
776 // -------------------------------------------------------
777 // d b H i e r L e v e l
778 // -------------------------------------------------------
779 dbHierLevel::dbHierLevel(dbView* adoptedView, OOF_mixOutlineItemFactory* adoptedFactory) :
780  mView(adoptedView),
781  mItemFactory(adoptedFactory)
782 {
783  if (!mItemFactory)
784  mItemFactory = this; // recursive pattern is simpler than having default be new'd
785 }
786 
787 
788 dbHierLevel::dbHierLevel(dbView* adoptedView, const dbBool& isLeafField) :
789  mView(adoptedView)
790 {
791  assert(adoptedView);
792  assert(isLeafField.fieldTable()->tableNumber()==adoptedView->table()->tableNumber());
793  mItemFactory = new dbOutlineItemFactory(isLeafField.fieldNumber());
794 }
795 
796 
798 {
799  delete mView;
800  if (mItemFactory!=this)
801  delete mItemFactory;
802 }
803 
804 
805 void
807 {
808  if (mItemFactory!=this)
809  delete mItemFactory;
810  mItemFactory = adoptedFactory;
811 }
812 
813 
814 LOutlineItem*
815 dbHierLevel::makeNestedOutlineItem(oidT inOID, dbHierBrowseHelper* inHelper, unsigned short indentLevel)
816 {
817  LOutlineItem* ret = mItemFactory->makeItem(inOID, inHelper, indentLevel);
818  return ret;
819 }
820 
821 
822 dbHierLevel*
824 {
825  return 0; // must override for recursive levels
826 }
827 
828 
829 
830 // -------------------------------------------------------
831 // d b H i e r R e l a t e d L e v e l
832 // -------------------------------------------------------
833 dbHierRelatedLevel::dbHierRelatedLevel(dbView* adoptedView, dbRelRefBase* inTraversalField, OOF_mixOutlineItemFactory* adoptedFactory) :
834  dbHierLevel(adoptedView, adoptedFactory),
835  mTraversalField(inTraversalField)
836 {
837 // this version of ctor exists mainly so can pass in just dbView, as bottom-most of fixed set of levels
838 // note that the assert below has to differ slightly to allow for this circumstance
839 
840 // big danger is traversal field is on different table, so creates related selection that the
841 // next level doesn't see. A dbView may clone the table passed into it so we need this safety check.
842 
843 // Regardless, they must be on the same prototypical table hence we compare table numbers
844 // (effectively the same table class, except OOFILE allows you to instantate a class several times
845 // for different physical databases, so I have to be careful about using the term 'same class')
846  assert(!mTraversalField || mTraversalField->fieldTable()->tableNumber() == mView->table()->tableNumber());
847 
848  if (mTraversalField) {
849  const dbTable* const viewTable = mView->table();
850  if (mTraversalField->fieldTable() !=viewTable)
851  mTraversalField = (dbRelRefBase*) viewTable->field(mTraversalField->fieldNumber()); // safe downcast
852  }
853 }
854 
855 
856 dbHierRelatedLevel::dbHierRelatedLevel(dbView* adoptedView, dbRelRefBase& inTraversalField, OOF_mixOutlineItemFactory* adoptedFactory) :
857  dbHierLevel(adoptedView, adoptedFactory),
858  mTraversalField(&inTraversalField)
859 {
860 // see first ctor for big explanation of this assert
861  assert(mTraversalField->fieldTable()->tableNumber() == mView->table()->tableNumber());
862 
863  const dbTable* const viewTable = mView->table();
864  if (mTraversalField->fieldTable() !=viewTable)
865  mTraversalField = (dbRelRefBase*) viewTable->field(mTraversalField->fieldNumber()); // safe downcast
866 }
867 
868 
869 dbHierRelatedLevel::dbHierRelatedLevel(dbView* adoptedView, dbRelRefBase& inTraversalField, const dbBool& isLeafField) :
870  dbHierLevel(adoptedView, isLeafField),
871  mTraversalField(&inTraversalField)
872 {
873 // see first ctor for big explanation of this assert
874  assert(mTraversalField->fieldTable()->tableNumber() == mView->table()->tableNumber());
875 
876  const dbTable* const viewTable = mView->table();
877  if (mTraversalField->fieldTable() !=viewTable)
878  mTraversalField = (dbRelRefBase*) viewTable->field(mTraversalField->fieldNumber()); // safe downcast
879 }
880 
881 
882 unsigned long
884 {
885  unsigned long ret = 0;
886  if (mTraversalField) {
887  dbTable* rhs = selectNestedItemsFor(inOID);
888  ret = rhs->count();
889  }
890  return ret;
891 }
892 
893 
894 dbTable*
896 {
897  dbTable* ret = 0;
898  if (mTraversalField) {
899  mView->table()->selectJustOID(inOID);
900  assert(mView->table()->count()==1);
901  mView->table()->start(); // just try
902  ret = mTraversalField->relatedTable();
904  }
905  return ret;
906 }
907 
908 
909 
910 
911 // -------------------------------------------------------
912 // d b H i e r R e c u r s i v e R e l a t e d L e v e l
913 // -------------------------------------------------------
915  dbHierRelatedLevel(adoptedView, inTraversalField, adoptedFactory)
916 {}
917 
918 
920  dbHierRelatedLevel(adoptedView, inTraversalField, adoptedFactory)
921 {}
922 
923 
924 dbHierRecursiveRelatedLevel::dbHierRecursiveRelatedLevel(dbView* adoptedView, dbRelRefBase& inTraversalField, const dbBool& isLeafField) :
925  dbHierRelatedLevel(adoptedView, inTraversalField, isLeafField)
926 {}
927 
928 
929 dbHierLevel*
931 {
932  assert(mTraversalField);
933  assert(mTraversalField->fieldTable() == mView->table());
934  dbTable* nestedTable = mTraversalField->relatedTable();
935  assert(mTraversalField->fieldTable()->tableNumber() == nestedTable->tableNumber()); // proof of recursion
936  dbView* orphanedView = new dbView(*mView, nestedTable); // copy view but in related clone table
937  dbRelRefBase* nestedTraversalField = (dbRelRefBase* ) nestedTable->field(mTraversalField->fieldNumber()); // safe downcast, given asserts
938  dbHierLevel* ret = new dbHierRecursiveRelatedLevel(orphanedView, nestedTraversalField, mItemFactory);
939  return ret;
940 }
bool value() const
Definition: oof4.h:1529
OOF_mixOutlineItem * highlightedItem() const
Definition: oofpphier.cpp:627
unsigned long nextCacheIndex()
Definition: oofpphier.cpp:325
virtual dbTable * selectNestedItemsFor(oidT)=0
void GetDrawContentsFromView(const STableCell &inCell, SOutlineDrawContents &ioDrawContents)
Definition: oofpphier.cpp:153
unsigned long countNestedItemsFromLevel(oidT, unsigned short) const
Definition: oofpphier.cpp:414
Link a dbView to one specific level in a tree control.
Definition: oofpphier.h:69
unsigned long count()
Count records in current selection.
Definition: oof1.h:2017
void initCacheRow(unsigned long cacheIndex, fieldNumT numFields)
Definition: oofpphier.cpp:355
Abstract manager coordinating dbHelper objects that manage interaction on a window.
Definition: oofgui.h:301
dbView * mView
Definition: oofpphier.h:214
fieldNumT fieldNumber() const
Definition: oof3.h:754
const dbField & defaultFindField() const
Definition: oofview.cpp:253
tableNumT tableNumber() const
Definition: oof1.h:2376
virtual dbSelection highlightedSelection() const
Definition: oof3.h:26
Highest level used to assemble queries.
Definition: oofquery.h:46
unsigned long count() const
Definition: oof2.cpp:770
virtual void ClickCell(const STableCell &inCell, const SMouseDownEvent &inMouseDown)
Definition: oofpphier.cpp:77
Envelope class to contain an abstract selection apart from its dbTable.
Definition: oof1.h:316
Macintosh structure for a rectangle.
const OOFmsgT OOFmsg_GetDisplayTableHandler
Definition: oofmsg.h:64
dbTable * relatedTable()
Definition: oofrel.cpp:1074
void start()
Definition: oof1.cpp:2057
unsigned short deepestIndent() const
Definition: oofpphier.h:295
unsigned short indentLevel() const
Definition: oofpphier.h:329
unsigned long count() const
Definition: oofarray.h:126
const dbField & field(unsigned int) const
Definition: oofview.h:206
virtual void calculateWidths(unsigned long widthToDivide, unsigned short colSepWidth=0)
Definition: oofsize.cpp:117
Abstract for factory making recursive levels.
Definition: oofpphier.h:193
dbOutlineItemFactory(fieldNumT leafFieldNum)
virtual dbHierLevel * makeNestedLevel() const
factory for recursive levels, may return 0 if unable to recurse
virtual bool receiveMsg(OOFmsgT msg, unsigned long senderDefined)
The default receiveMsg behaviour is to delete yourself when the broadcaster closes.
dbHierLevel * lowestLevel() const
Definition: oofpphier.h:276
virtual OOF_fieldTypes fieldType() const
Definition: oof4.cpp:1077
LOutlineItem * makeNestedOutlineItem(oidT inOID, dbHierBrowseHelper *inHelper, unsigned short indentLevel)
methods for making outline items, or changing the factory used to make them
bool search(const dbQueryClause &query)
Definition: oof1.cpp:2348
virtual void highlightRecNo(unsigned long, bool bSelect=TRUE) const
Specify or calculate a set of column widths & alignments.
Definition: oofsize.h:51
virtual ~dbHierLevel()
unsigned long width(unsigned short colNum)
Definition: oofsize.cpp:195
Common binary query for field, eg: People.Salary > 90000.
Definition: oofquery.h:165
void deleteAllCells(bool alwaysDeleteStorage=false)
Effectively delete cells by resetting mNextFreeEntry cursor.
Definition: oofarray.cpp:219
OOF_mixOutlineItem(oidT, dbHierBrowseHelper *, unsigned short indentLevel, bool isLeaf)
Definition: oofpphier.cpp:114
virtual ~dbHierBrowseHelper()
Definition: oofpphier.cpp:241
dbHelper for managing lists of records.
Definition: oofgui.h:372
Create LOutlineItem's for each item displayed in tree control.
Definition: oofpphier.h:171
Parent for any field that is a relationship to another table.
Definition: oofrel.h:19
void setCachedContents(unsigned long cacheIndex, fieldNumT fieldNum, char *adoptedStr)
Definition: oofpphier.cpp:379
oidT findOIDforData(const void *inDataPtr, UInt32 inDataSize) const
Definition: oofpphier.cpp:193
dbHierBrowseHelper(LOutlineTable *inTable=0)
Definition: oofpphier.cpp:232
Provide an iterable set of fields.
Definition: oofview.h:26
void deleteContentsCache()
Definition: oofpphier.cpp:335
void appendLevel(dbHierLevel *adoptedLevel)
Definition: oofpphier.cpp:397
LHS argument to queries on fields.
Definition: oofquery.h:572
virtual void insertItemsBelow(LOutlineItem *, OOF_mixOutlineItem *)
Definition: oofpphier.cpp:434
virtual dbHierLevel * level() const
Definition: oofpphier.cpp:131
void IncludeAllBelowItem(unsigned short inIndentLevel, oidT, dbSelection &) const
Definition: oofpphier.cpp:565
virtual unsigned long countNestedItemsFor(oidT)=0
dbTable * baseTableOfRelationChain()
Definition: oof1.cpp:1984
oidT highlightedOID() const
Definition: oofpphier.cpp:484
unsigned long oidT
type we pass around pretending we have a real OID.
Definition: oof1.h:229
dbHierLevel * level(unsigned short) const
Definition: oofpphier.h:268
bool relateRecord(bool broadcastChange=true)
Definition: oofrel.cpp:507
Mixin for factories that make LOutlineItem's.
Definition: oofpphier.h:155
virtual ~dbViewOutlineItem()
Definition: oofpphier.cpp:46
virtual dbView * view() const
Definition: oofpphier.cpp:124
dbViewOutlineItem(oidT, dbHierBrowseHelper *, unsigned short indentLevel, bool isLeaf)
Definition: oofpphier.cpp:40
dbSelection currentSelection()
Definition: oof1.cpp:2674
void setSelection(const dbSelection &)
Definition: oof1.cpp:2725
Manage a tree control linked to one or more dbView's.
Definition: oofpphier.h:96
virtual void ExpandSelf()
Definition: oofpphier.cpp:60
virtual bool receiveMsg(OOFmsgT msg, unsigned long senderDefined)
The default receiveMsg behaviour is to delete yourself when the broadcaster closes.
Definition: oofgui.cpp:348
const char * getCachedContents(unsigned long cacheIndex, fieldNumT fieldNum)
Definition: oofpphier.cpp:368
Save & restore current database selection on the stack.
Definition: oof1.h:392
dbField * field(fieldNumT) const
Definition: oof1.h:2355
bool isLeaf() const
Definition: oofpphier.h:315
Persistent field used to store a boolean.
Definition: oof4.h:367
Declare query classes.
unsigned int count() const
Definition: oof1.h:1498
unsigned short fieldNumT
Definition: oof1.h:276
LOutlineTable * mOutlineTable
Definition: oofpphier.h:144
Base class for persistent tables.
Definition: oof1.h:452
PowerPlant base class for managing an item in a hierarchical tree.
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
Definition: oof3.h:26
dbView * viewAtLevel(unsigned short) const
Definition: oofpphier.cpp:424
dbGUI * getGUI()
Definition: oof1.cpp:2557
OOF_ExpandableLongArray mContentsCache
Definition: oofpphier.h:146
virtual void updateBrowserSelection() const
void append(unsigned long)
Definition: oofarray.cpp:131
Map LOutlineItem to specific record.
Definition: oofpphier.h:35
bool IsLeaf(dbHierBrowseHelper *, unsigned short indentLevel)
void resetTableAfterViewRestructure()
Definition: oofpphier.cpp:284
oidT FirstOIDBelowItem(unsigned short inIndentLevel, oidT inOID) const
Definition: oofpphier.cpp:594
void setAlternateItemFactory(OOF_mixOutlineItemFactory *adoptedFactory)
unsigned long mNextCacheIndex
Definition: oofpphier.h:145
RHS String argument to queries on fields like dbChar.
Definition: oofquery.h:324
virtual void GetDrawContentsSelf(const STableCell &inCell, SOutlineDrawContents &ioDrawContents)
Definition: oofpphier.cpp:67
OOF_ExpandableLongArray mHierLevels
Definition: oofpphier.h:143
virtual oofString copyString() const
Definition: oof3.cpp:472
void browseViewWithTable(LOutlineTable *inTable)
Definition: oofpphier.cpp:389
virtual OOF_fieldTypes fieldType() const =0
unsigned long OOFmsgT
Definition: oofmsg.h:31
virtual LOutlineItem * makeItem(oidT inOID, dbHierBrowseHelper *inHelper, unsigned short indentLevel)
bool selectJustOID(oidT)
Try to change the current selection to just the matching record.
Definition: oof1.cpp:2705
virtual Boolean CanExpand() const
Definition: oofpphier.cpp:52
dbView * view() const
Definition: oofpphier.h:305
virtual void highlightNothing() const
virtual unsigned long highlightedRecNo() const
oidT oid() const
Definition: oofpphier.h:322
Stack class to change cursor for a simple scope.
Definition: stSetCursor.h:26
OOF_mixOutlineItemFactory * mItemFactory
Definition: oofpphier.h:215
oidT currentOID()
Absolute record address of current record.
Definition: oof1.h:1938
virtual void refreshBrowser()
Definition: oofpphier.cpp:316
virtual dbView * view() const
dbTable * table() const
Definition: oofview.h:109
Base for the RHS arguments to combinatorial queries dbQueryBinary, dbQueryTrinary.
Definition: oofquery.h:307
Base class for persistent fields in dbTable's.
Definition: oof3.h:63
virtual LOutlineItem * makeItem(oidT inOID, dbHierBrowseHelper *inHelper, unsigned short indentLevel)
unsigned long value(unsigned long index) const
Definition: oofarray.cpp:243
dbHierBrowseHelper * mHelper
Definition: oofpphier.h:56
virtual void subscribeTo(oofBroadcaster *)
Definition: oofmsg.cpp:293