OOFILE  1.9
oofriXML.cpp
Go to the documentation of this file.
1 // COPYRIGHT 1999 A.D. Software, All rights reserved
2 // oofriXML.cpp
3 // Input of reports from XML
4 // see .h file for more details on the XML parser xpatpp
5 
6 #ifdef OOF_RW_READ_REPORTS
7 
8 #ifndef _STDIO_H
9  #include <stdio.h>
10 #endif
11 #ifndef _STRING_H
12  #include <string.h>
13 #endif
14 #ifndef H_oofSting
15  #include "oofSting.h"
16 #endif
17 #ifndef H_OOFGRPHS
18  #include "oofGrphs.h"
19 #endif
20 #ifndef H_OOFRIXML
21  #include "oofriXML.h"
22 #endif
23 #ifndef H_OOFREL
24  #include "oofrel.h"
25 #endif
26 #ifndef H_OOF4
27  #include "oof4.h" // for dbBool
28 #endif
29 
30 #ifdef OOF_MEM_DEBUG_LAST_INCLUDE
31  #include OOF_MEM_DEBUG_LAST_INCLUDE
32 #endif
33 
34 #ifndef OOF_NO_STDLIB
35  #ifndef std
36  using namespace std;
37  #endif
38 #endif
39 
40 
54 enum xmlRepParseStateT {
56  eIdle=0,
65  eInBlock=0x100,
66  eInBody=0x200,
69  eInTable=0x1000,
70  eInPageHeader=0x2000,
71  eInPageFooter=0x4000,
72  eInColumn=0x8000,
73  eInWidth=0x10000,
74  eInCustomCode=0x20000
75 };
76 
77 
78 // -------------------------------------------------------
79 // settings and style managers
80 // local class declarations
81 // -------------------------------------------------------
82 
83 enum { kCompletePromiseMsg='Prom' };
84 
94 public:
95 
97  mCSSstring(inCSS)
98  {};
100  virtual void completePromises()=0;
101 
102  const char* findStringForID(const oofString& theID) const { return findStringForID(theID, mCSSstring); };
103  static const char* findStringForID(const oofString& theID, const char* inString);
104 
105 // data
106  const oofString& mCSSstring; // assumes someone else maintains, just using us
107 };
108 
109 
110 class oofPromisedGraphSettings; // forward
111 
119 public:
121  virtual ~oofGraphSettingsCompleter();
122 
123  virtual void completePromises();
124  void completeSettings(const oofString& inID, oofGraph*) const; // callback from listener
125 
126  static oofGraphSettingsCompleter* currentlyConstructing() { return sCurrentlyConstructing; };
127 
128 private:
129  static oofGraphSettingsCompleter* sCurrentlyConstructing;
130 };
131 
132 
133 class oofPromisedRepTextStyle;// forward
134 
142 public:
144  virtual ~oofRepTextStyleCompleter();
145 
146  virtual void completePromises();
147  void completeStyle(oofPromisedRepTextStyle*) const; // callback from listener
148 
149  static oofRepTextStyleCompleter* currentlyConstructing() { return sCurrentlyConstructing; };
150 
151 private:
152  static oofRepTextStyleCompleter* sCurrentlyConstructing;
153 };
154 
155 
163 protected: // only use as mixin so protect ctor etc.
164  OOF_mixPromise(oofRepPromiseCompleter* listensTo, const oofString& theID) :
165  oofSingleListener(listensTo),
166  mID(theID)
167  {};
168  // uses default copy ctor, dtor
169 
170 public:
171  const oofString& ID() const { return mID; };
172 
173 protected:
174 // data storage
175  const oofString mID;
176 };
177 
178 
188 public:
190  OOF_mixPromise(c, theID)
191  {};
193  OOF_mixPromise(oofRepTextStyleCompleter::currentlyConstructing(), theID)
194  {};
195  // use default copy ctor, dtor
196 
197  virtual bool receiveMsg(OOFmsgT msg, unsigned long senderDefined);
198  virtual oofRepTextStyle* clone() const;
199 };
200 
201 
210 public:
212  OOF_mixPromise(c, theID),
213  mGraph(G)
214  {};
216  OOF_mixPromise(oofGraphSettingsCompleter::currentlyConstructing(), theID),
217  mGraph(G)
218  {};
219  // use default copy ctor, dtor
220  virtual bool receiveMsg(OOFmsgT msg, unsigned long senderDefined);
221 
222 private:
223  oofGraph* mGraph;
224 };
225 
226 
227 // -------------------------------------------------------
228 // O O F _ r e p X M L s t y l e C l e a n u p V i s i t o r
229 // -------------------------------------------------------
230 
237 protected:
238  virtual void VisitDrawable(oofRepDrawable*);
239 };
240 
241 
246 void
248 {
249  assert(inDrawable);
250  oofRepTextStyle* drawableStyle = inDrawable->textStyle();
251  if (drawableStyle && !drawableStyle->invariant())
252  inDrawable->textStyle(0); // delete incomplete styles
253 }
254 
255 
256 // -------------------------------------------------------
257 // O O F _ r e p X M L c l e a r I D V i s i t o r
258 // -------------------------------------------------------
266 protected:
267  virtual void VisitDrawable(oofRepDrawable*);
268 };
269 
270 
271 void
273 {
274  inDrawable->clearID();
275 }
276 
277 
278 // -------------------------------------------------------
279 // O O F _ r e p X M L a d o r n e r L i n k V i s i t o r
280 // -------------------------------------------------------
281 
288 public:
290  mCallerDict(adornerDict)
291  {};
292 
293 protected:
294  virtual void VisitDrawable(oofRepDrawable*);
295 
296 // data storage
298 };
299 
300 
301 void
303 {
304  const oofString theID = inDrawable->ID();
305  if (!theID.isEmpty()) {
306  OOF_adornerHolder* existingHolder = (OOF_adornerHolder*)mCallerDict[theID]; // safe downcast
307  if (existingHolder)
308  inDrawable->adorners().adopt(existingHolder->adorners());
309  }
310 }
311 
312 
313 // -------------------------------------------------------
314 // O O F _ X M L r e p P a r s e r S t a t e
315 // -------------------------------------------------------
321 private:
323 
325  //setters
326  void saveOldState(bool clearNew=true);
327  void restoreOldState();
328  void set(unsigned int inState);
329  void clear(unsigned int inState);
330 
331 
332  // getters
333 
334  unsigned int getRepBuildState();
335 
336 private:
337  unsigned int mRepGenState;
338  OOF_ExpandableLongArray mOldState;
339 };
340 
341 
342 inline void
343 OOF_XMLrepParserState::set(unsigned int inState)
344 {
345  mRepGenState = mRepGenState | inState;
346 
347 }
348 
349 
350 inline void
351 OOF_XMLrepParserState::clear(unsigned int inState)
352 {
353  mRepGenState = mRepGenState &(~inState);
354 
355 }
356 
357 
358 // getters
359 inline unsigned int
360 OOF_XMLrepParserState::getRepBuildState()
361 {
362  return mRepGenState;
363 }
364 
365 
366 // -------------------------------------------------------
367 // O O F _ X M L r e p P a r s e r
368 // -------------------------------------------------------
379 OOF_XMLrepParser::OOF_XMLrepParser(dbConnect* inDB) :
380  mReport(0),
381  mMultiRep(0),
382  mDB(inDB),
383  mTextStyleCompleter(0),
384  mGraphSettingsCompleter(0),
385  mAdornerDict(10, 2, true /* owns contents*/)
386 {
387 }
388 
389 
390 OOF_XMLrepParser::OOF_XMLrepParser(expatppNesting* parent, dbConnect* inDB) :
391  expatppNesting(parent),
392  mReport(0),
393  mMultiRep(0),
394  mDB(inDB),
395  mTextStyleCompleter(0),
396  mGraphSettingsCompleter(0)
397 {
398 }
399 
400 
402 {
403  const XML_Error err = XML_GetErrorCode();
404  if (err==0) {
405  // DEBUGGING ONLY - extract the data we've parsed
406 #if 0
407  {
408  ofstream dumpFile("OOF_XMLrepParser.dump");
409  mDB->describe(dumpFile);
410  mDB->extract(dumpFile);
411  dumpFile.close();
412  }
413 #endif
414  assert(mDepth==0); // completed parsing
415  assert(!mReport); // otherwise not much point in using! - user failed to retrieve report
416  assert(!mTextStyleCompleter);
417  assert(!mTextStyleCompleter);
418  }
419  else { // cleanup to avoid leaks just because bad file
420  delete mReport;
421  delete mTextStyleCompleter;
423  }
424 }
425 
426 
427 XML_Status
429 {
430  XML_Status ret = XML_STATUS_OK;
431  stSaveDirectory returnToCurrentDirWhenDone;
432  const oofDirectory fileDir = theFile.directory();
433  fileDir.gotoDirectory(); // ANSI file open gets name alone
434  const oofString theFilename = theFile.filename();
435 
436 //largely copied from the sample code
437  FILE* xmlFile;
438  char buf[BUFSIZ];
439  int done;
440  int depth = 0;
441 
442  xmlFile = fopen(theFilename, "r");
443  if (xmlFile) {
444  do { // loop reading the file in a fixed size buffer
445  size_t len = fread(buf, 1, sizeof(buf), xmlFile /*stdin*/);
446  done = (len < sizeof(buf));
447  if (!XML_Parse(buf, len, done)) {
448  #ifdef OOF_DEBUG
449  /*
450  from original sample
451  fprintf(stderr,
452  "%s at line %d\n",
453  XML_ErrorString(XML_GetErrorCode()),
454  XML_GetCurrentLineNumber());
455  */
456  dbConnect::raise( stringstream() << flush
457  << "OOF_XMLrepParser::parseFile error '"
458  << XML_ErrorString(XML_GetErrorCode())
459  << "' at line " << XML_GetCurrentLineNumber(),
460  false /* don't terminate */
461  );
462  #endif
463  ret=XML_STATUS_ERROR;
464  break;
465  }
466  } while (!done);
467  fclose(xmlFile);
468  }
469  return ret;
470 }
471 
472 
477 oofRep*
479 {
480  oofRep* ret = mReport;
481  mReport = 0;
482  return ret;
483 }
484 
485 
489 void
490 OOF_XMLrepParser::startElement(const char* name, const char** atts)
491 {
492  if(strcmp(name,"report")==0)
493  startElem_report(atts);
494 
495  else if(strcmp(name,"section")==0)
496  startElem_section(atts);
497 
498  else if(strcmp(name,"style")==0)
499  startElem_style(atts);
500 
501  else if(strcmp(name,"adorners")==0)
502  startElem_adorners(atts);
503 
504  else if(strcmp(name,"layout")==0)
505  startElem_layout(atts);
506 
507  else if(strcmp(name,"schema")==0)
508  startElem_schema(atts);
509 
510  else
511  startUnknownElem(name, atts);
512 
513 }// end start element
514 
515 
516 void
518 {
519  assert(!mReport);
520  assert(mDepth==1); // report is root element
521  if (atts[0] && (strcmp(atts[0], "ID")==0)) {
522  mID = atts[1];
523  if (atts[2]) // GROSS ASSUMPTION - any attribute on <report> after ID means it's multi
524  mMultiRep = new oofRepMulti;
525  else
526  mReport = new oofRep;
527  }
528  else {
529  mID = "1";
530  mReport = new oofRep;
531  }
532  }
533 
534 
535 void
537 {
538  assert(mDepth==2); // can only get section immediately within report
539  assert(mMultiRep);
540  assert(!mReport);
541  mReport = new oofRepSection;
542  assert(atts[0] && (strcmp(atts[0], "ID")==0));
543  mID = atts[1];
544  }
545 
546 
547 void
549 {
550  new OOF_XMLrepStyleParser(this, mStyleString); // self-deleting sub parser
551  }
552 
553 
554 void
556 {
557  new OOF_XMLrepAdornerParser(this, mAdornerDict); // self-deleting sub parser
558  }
559 
560 
561 void
563 {
564  assert(!mTextStyleCompleter);
566 
567  assert(!mGraphSettingsCompleter);
569  new OOF_XMLrepLayoutParser(this, mDB); // self-deleting sub parser
570  }
571 
572 
573 void
575 {
576  new oofXMLschemaParser(this); // self-deleting sub parser
577  }
578 
579 
580 void
581 OOF_XMLrepParser::startUnknownElem(const char* name, const char** atts)
582 {
583  oofXMLdataParser* dataParser = new oofXMLdataParser(this, mDB); // self-deleting sub parser
584  mDepth--; // this is not our tag - so we didn't really go down this far
585  nestedStartElementCallback(dataParser, name, atts); // give this tag to the sub-parser
586  // NOTE the difference in this case from the others is that we don't have a wrapping tag
587  // within which we invoke the sub-parser. If all the data was wrapped in a <data> tag
588  // then this case would be as simple as the earlier ones
589  }
590 
591 
592 
593 
594 
611 void
613 {
614  if(strcmp(name,"report")==0)
615  endElem_report();
616 
617  else if(strcmp(name,"section")==0)
618  endElem_section();
619 
620  else if(strcmp(name,"style")==0)
621  endElem_style();
622 
623  else if(strcmp(name,"adorners")==0)
625 
626  else if(strcmp(name,"layout")==0)
627  endElem_layout();
628 
629  else if(strcmp(name,"schema")==0)
630  endElem_schema();
631 
632  else
633  endUnknownElem(name);
634 
635 }// end element
636 
637 
638 void
640 {
641  assert(mDepth==1); // report is root element
642  if (mMultiRep) {
643  assert(!mReport); // section finished
644  mReport = mMultiRep; // finally we return the report regardless of single or multi
645  }
646  else
647  FinishReport(); // multi rep reports call at end of <section>
648  assert(mReport);
649  }
650 
651 
652 void
654 {
655  assert(mDepth==2); // can only get section immediately within report
656  assert(mMultiRep);
657  assert(mReport);
658  FinishReport();
660  mReport=0;
661  }
662 
663 
664 void
666 {
667 // unused default, override as needed
668 }
669 
670 
671 void
673 {
674 // unused default, override as needed
675 }
676 
677 
678 void
680 {
681 // unused default, override as needed
682 }
683 
684 
685 void
687 {
688  assert(!mDB); // only one schema!
690  assert(mDB);
692  XMLsettings->createTempConnectFiles(mDB); // user overrideable function
693  }
694 
695 
696 void
697 OOF_XMLrepParser::endUnknownElem(const char* /*name*/)
698 {
699 // unused default, override as needed
700 }
701 
702 
708 void
710 {
711  assert(mReport);
712  const char* styleString = oofRepPromiseCompleter::findStringForID(mID, mStyleString);
713  if (styleString)
715 
716  assert(mTextStyleCompleter);
718  delete mTextStyleCompleter;
720 
721  assert(mGraphSettingsCompleter);
725 
726  mStyleString=""; // clear for the next one
727 
728  OOF_repXMLstyleCleanupVisitor styleCleaner;
729  styleCleaner.visit(mReport); // remove any styles that weren't init'd above
730  // usually caused by having to have an ID on an object but no matching
731  // style - at runtime they will use a cascaded style
732 
734  adornerLinker.visit(mReport); // link adorners
736 
737  OOF_repXMLclearIDVisitor clearIDsLast; // just to be safe
738  clearIDsLast.visit(mReport); // remove any styles that weren't init'd above
739 }
740 
741 
742 // -------------------------------------------------------
743 // O O F _ X M L r e p L a y o u t P a r s e r
744 // -------------------------------------------------------
745 
750 OOF_XMLrepLayoutParser::OOF_XMLrepLayoutParser(OOF_XMLrepParser* parent, dbConnect* inDB) :
751  expatppNesting(parent),
752  mDB(inDB),
753  mReport(parent->buildingReport()),
754  mCurrentBreakBand(0),
755  mCurrentLayout(0)
756 {
757  mBuildState = new OOF_XMLrepParserState;
758 }
759 
760 
762 {
763  assert(
764  (mParser && XML_GetErrorCode()!=0) || // !mParser if cleanly exit nested parser
765  (mDepth==0)
766  ); // completed parsing or error exit
767  delete mBuildState;
768 }
769 
770 
772 OOF_XMLrepLayoutParser::CurrentViewBand() const
773 {
774  oofRepViewBand* ret;
775  const int viewLevel = mTablesStack.count()-1;
776  if (viewLevel>=0)
777  ret = (oofRepViewBand*)(mTablesStack.value(viewLevel));
778  else
779  ret = 0;
780  return ret;
781 }
782 
783 
791 dbTable*
792 OOF_XMLrepLayoutParser::GetDatabaseInContext(const char** atts, unsigned short startAttribute, const char* attName)
793 {
794  dbTable* ret = 0;
795 
796 // find the 'source' attribute, allowing caller to save time by specifying startAttribute
797  unsigned short sourceIndex;
798  for (sourceIndex=startAttribute; atts[sourceIndex]; sourceIndex+=2) {
799  if (strcmp(atts[sourceIndex], attName)==0) {
800  break;
801  }
802  }
803  const oofString sourceName = oofTagMaker::decodeName( atts[sourceIndex+1] );
804  const unsigned int currentState = mBuildState->getRepBuildState();
805  if(currentState&eInTable) {
806  if (currentState & (eInHeaderBreak|eInFooterBreak)) { // try to lookup related table
807  oofRepViewBand* parentViewBand = CurrentViewBand();
808  assert(parentViewBand);
809  dbView* parentView = parentViewBand->view();
810  assert(parentView);
811  dbTable* parentTable = parentView->table();
812  if (parentTable) { // views can have null tables
813  dbField* theField = parentTable->field(sourceName); // rel field has same name as table
814  if (theField) { // found a match so looks like nesting !
815  assert(theField->fieldType()==relationshipField);
816  dbRelRefBase* rel2rhs = (dbRelRefBase*)theField; // safe downcast
817  ret = rel2rhs->relatedTable(); // RECURSE into nested table
818  }
819  } // lookup nested rel from table
820  } // in break of table
821  } // in table
822  if (!ret) // didn't find related table above
823  ret = mDB->table(sourceName); // lookup at top level of connection
824  return ret;
825 }
826 
827 
828 void
829 OOF_XMLrepLayoutParser::OpenTable(const char* /*name*/, const char** atts)
830 {
831  dbTable* theTable = GetDatabaseInContext(atts);
832  mBuildState->saveOldState(); // eg: in a header or footer of table
833  mBuildState->set(eInTable);
834  assert(theTable); // otherwise <layout> refers to different DB schema
835 
836  dbView* adoptedView = theTable->makeView(); // assumption is that table represents the view we saved
837  // so creating a view from the table with all fields is simply restoring the original view
838  // (but in the process additional fields in the table, outside the view) have been lost
839 
840  oofRepViewBand* theBand = new oofRepViewBand(adoptedView, false /* default not boxed*/);
841  if (atts[0] && (strcmp(atts[0], "ID")==0)) {
842  mCurrentCSSID = atts[1];
843  theBand->textStyle(new oofPromisedRepTextStyle(mCurrentCSSID));
844  theBand->ID(mCurrentCSSID);
845  }
846  mTablesStack.append(theBand);
847 }
848 
849 
854 void
855 OOF_XMLrepLayoutParser::startElement(const char* name, const char** atts)
856 {
857  const unsigned long currentState = mBuildState->getRepBuildState();
858 
859  if(currentState & eInColumn) { // optimise a bit by using state as quick check
860  if(strcmp(name,"header")==0)
861  mBuildState->set(eInHeader);
862  else if(strcmp(name,"width")==0)
863  mBuildState->set(eInWidth);
864  else if(strcmp(name,"customDrawer")==0) {
865  mBuildState->set(eInCustomCode);
866  oofXMLserializableParser* theParser = new oofXMLserializableParser(this, &mCurrentSerializable); // self-deleting sub parser
867  }
868  else
869  assert(!"unrecognised state inside a column"); //lint !e506 constant Boolean
870  }
871  else if(strcmp(name,"inline")==0){
872  BuildBlock(atts);
873  }
874  else if(strcmp(name,"header")==0){
875  OpenHeaderOrFooter(atts, eInFirstPageHeader, eInHeader);
876  }
877  else if(strcmp(name,"footer")==0){
878  OpenHeaderOrFooter(atts, eInFirstPageFooter, eInFooter);
879  }
880  else if(strcmp(name,"space")==0){
881  BuildSpaceBand( atts);
882  }
883  else if(strcmp(name,"column")==0){
884  OpenColumn( atts);
885  }
886  else if(strcmp(name,"box")==0){
887  OpenLayout(atts);
888  }
889  else if(strcmp(name,"table")==0){
890  OpenTable(name, atts);
891  }
892  else if(strcmp(name,"HR")==0){
893  BuildLineBand(atts);
894  }
895  else if(strcmp(name,"headerBreaks")==0){
896  assert ( ! (mBuildState->getRepBuildState() & (eInHeaderBreak|eInFooterBreak)) ) ;// guards against nested breaks
897  mBuildState->set(eInHeaderBreak);
898  }
899  else if(strcmp(name,"footerBreaks")==0){
900  mBuildState->set(eInFooterBreak);
901  }
902  else if(strcmp(name,"break")==0){
903  assert(!mCurrentBreakBand);
904  mCurrentBreakNewPageEveryTime = (atts[0]!=0); // assume any break attribute = YES
905  // see endElement for construction of break after we've picked up any tables
906  // etc. within it
907  }
908  else if(strcmp(name,"graph")==0){
909  BuildGraphBand(atts);
910  }
911 // ignore BR
912 
913  mCharData.clear();
914 }// end start element
915 
916 
917 
923 void
924 OOF_XMLrepLayoutParser::charData(const char* s, int len)
925 {
926  const unsigned long currentState = mBuildState->getRepBuildState();
927  if(currentState & currentState & (eInLayoutBand | eInBlock | eInColumn)) {
928  const bool wantEmpty = currentState & (eInColumn & eInHeader);
929  if (wantEmpty || !emptyCharData(s, len)){
930  oofString decodedString = oofString::utf8To8BitAscii(s,len);// convert from utf8 format
931  mCharData.append(decodedString, decodedString.length()); // don't need overhead of decoding - expat has done that for us
932  }
933  }
934 }
935 
936 
937 void
938 OOF_XMLrepLayoutParser::ParseAccumulatedCharData()
939 {
940  if (mCharData.isEmpty())
941  return;
942 
943  const unsigned long currentState = mBuildState->getRepBuildState();
944 
945  if(currentState & eInColumn) {
946  oofRepViewBand* theBand = CurrentViewBand();
947  assert(theBand);
948  dbView* theView = theBand->view();
949  if (currentState & eInHeader) {
950  theView->setHeading(mCurrentColNumber, mCharData);
951  // WARNING doesn't cope with linebreaks in headings
952  // would need to append to string before emptyCharData check above
953  // see oofXMLdataParser for examples
954  }
955  else if (currentState & eInWidth) {
956  oofColSizer* theSizer = theView->colSizer();
957  if (mCharData.endsWith('%')) {
958  mCharData.shorten(1); // drop the '%'
959  const unsigned long width = mCharData.asUnsignedLong();
960  theSizer->setFixedPercentage(mCurrentColNumber, width);
961  }
962  else {
963  const unsigned long width = mCharData.asUnsignedLong();
964  theSizer->setFixedWidth(mCurrentColNumber, width);
965  }
966  }
967 // else if (currentState & eInCustomCode)
968 // implemented with a sub-parser so should never get here except with empty content!
969 // else
970 // assert(!"unrecognised state inside a column"); //lint !e506 constant Boolean
971 // can have column which specifies only in attributes so no nested tags, eg:
972 //
973 // <column number='0' align='centre'>
974 // </column>
975  }
976  else if (currentState & (eInLayoutBand | eInBlock)) {
977  assert(mCurrentLayout);
978  oofRepTextStyle* textStyle;
979  if (mCurrentCSSID.isEmpty())
980  textStyle = 0;
981  else
982  textStyle = new oofPromisedRepTextStyle(mCurrentCSSID);
983 
984  const long pageSymbolAt = mCharData.find("^P");
985  if (pageSymbolAt==oofString::kNotFound)
986  mLastBlock = new oofRepTextBlock(mCharData, textStyle);
987  else {
988  const oofString leadingText = mCharData.subString(0, pageSymbolAt /* count */);
989  const oofString trailingText = mCharData.subString(pageSymbolAt+2 /* to end */);
990  mLastBlock = new oofRepPageNoBlock(leadingText, trailingText, textStyle);
991  }
992 
993  mLastBlock->align(mCurrentBlockAlign);
994  if (mCurrentBlockFixedWidth>0)
995  mLastBlock->fixedWidth(mCurrentBlockFixedWidth);
996 
997  if (textStyle)
998  mLastBlock->ID(mCurrentCSSID);
999  *mCurrentLayout << mLastBlock;
1000  }
1001 
1002  mCharData.clear();
1003 }//end chardata
1004 
1005 
1006 void
1008 {
1009  ParseAccumulatedCharData();
1010 
1011  const unsigned long currentState = mBuildState->getRepBuildState();
1012 // order in decreasing frequency of use
1013 
1014  if(currentState & eInColumn) { // optimise a bit by using state as quick check
1015  if(strcmp(name,"column")==0)
1016  mBuildState->restoreOldState();
1017  else if(strcmp(name,"header")==0)
1018  mBuildState->clear(eInHeader);
1019  else if(strcmp(name,"width")==0)
1020  mBuildState->clear(eInWidth);
1021  else if(strcmp(name,"customDrawer")==0) {
1022  mBuildState->clear(eInCustomCode);
1023  if (mCurrentSerializable) {
1024  oofRepViewBand* theBand = CurrentViewBand();
1025  oofRepCustomViewDrawer* theDrawer = dynamic_cast<oofRepCustomViewDrawer*>(mCurrentSerializable);
1026  assert(theDrawer);
1027  theBand->customDrawer(mCurrentColNumber, theDrawer);
1028  }
1029  }
1030  else
1031  assert(!"unrecognised state inside a column"); //lint !e506 constant Boolean
1032  }
1033  else if(strcmp(name,"inline")==0){
1034  mBuildState->clear(eInBlock);
1035  }
1036  else if(strcmp(name,"BR")==0){
1037  if (mLastBlock)
1038  mLastBlock->moveDownAfter(true);
1039  }
1040  else if(strcmp(name,"header")==0){
1041  if(currentState & eInFirstPageHeader)
1042  mBuildState->clear(eInFirstPageHeader);
1043  else
1044  mBuildState->clear(eInHeader);
1045  }
1046  else if(strcmp(name,"footer")==0){
1047  if(currentState & eInFirstPageFooter)
1048  mBuildState->clear(eInFirstPageFooter);
1049  else
1050  mBuildState->clear(eInFooter);
1051  }
1052  else if(strcmp(name,"table")==0){
1053  CloseTable();
1054  }
1055  else if(strcmp(name,"box")==0){
1056  mBuildState->clear(eInLayoutBand);
1057  CloseLayout();
1058  }
1059  else if(strcmp(name,"headerBreaks")==0){
1060  mBuildState->clear(eInHeaderBreak);
1061  }
1062  else if(strcmp(name,"footerBreaks")==0){
1063  mBuildState->clear(eInFooterBreak);
1064  }
1065  else if(strcmp(name,"break")==0){
1066  BuildBreak();
1067  }
1068 
1069 // ignore HR, graph
1070 }// end element
1071 
1072 
1073 void
1074 OOF_XMLrepLayoutParser::BuildBreak()
1075 {
1076  assert(mCurrentBreakBand);
1077  const int currentState = mBuildState->getRepBuildState();
1078  oofRepBreak* newBreak = new oofRepBreakEveryRecord(mCurrentBreakBand, mCurrentBreakNewPageEveryTime);
1079 // NOT YET IMPLEMENTED - choice of break types
1080 
1081  oofRepViewBand* theViewBand = CurrentViewBand();
1082  assert(theViewBand); // can only have a break occur within a view band
1083 
1084  if (currentState&eInHeaderBreak) {
1085  theViewBand->headerBreaks() << newBreak;
1086  }
1087  else {
1088  assert(currentState&eInFooterBreak);
1089  theViewBand->footerBreaks() << newBreak;
1090  }
1091 
1092  mCurrentBreakBand=0;
1093  mCurrentBreakNewPageEveryTime=false;
1094 }
1095 
1096 
1097 void
1098 OOF_XMLrepLayoutParser::OpenColumn(const char** atts)
1099 {
1100  // we ALWAYS have a column number attribute, but bow to the precedent in
1101  // other elements that an ID (if present) is the first attribute
1102  mBuildState->saveOldState();
1103  mBuildState->set(eInColumn);
1104 
1105  int colNumberAtt = 0;
1106  if (atts[0]) {
1107  if(strcmp(atts[0], "ID")==0) {
1108  mCurrentCSSID = atts[1];
1109  colNumberAtt = 2;
1110  }
1111  }
1112  else
1113  mCurrentCSSID = "";
1114 
1115  assert(atts[0] && (strcmp(atts[colNumberAtt], "number")==0));
1116  mCurrentColNumber = atoi(atts[colNumberAtt+1]);
1117 
1118  oofColSizer::colAlignT colAlign;
1119  const int alignAt = colNumberAtt+2;
1120  if(atts[alignAt] && (strcmp(atts[alignAt], "align")==0)) {
1121  const int alignValueAtt = alignAt+1;
1122  assert(atts[alignValueAtt]); // 2nd half of pair
1123  if(strcmp(atts[alignValueAtt], "centre")==0)
1124  colAlign = oofColSizer::alignCentre;
1125  else if(strcmp(atts[alignValueAtt], "right")==0)
1126  colAlign = oofColSizer::alignRight;
1127  else if(strcmp(atts[alignValueAtt], "left")==0)
1128  colAlign = oofColSizer::alignLeft;
1129  else
1130  colAlign = oofColSizer::alignJust;
1131 
1132  oofRepViewBand* theBand = CurrentViewBand();
1133  assert(theBand);
1134  dbView* theView = theBand->view();
1135  theView->colSizer()->setAlignment(mCurrentColNumber, colAlign);
1136  } // has alignment
1137  mCurrentSerializable = 0;
1138 }
1139 
1140 
1141 void
1142 OOF_XMLrepLayoutParser::BuildBlock(const char** atts)
1143 {
1144  int likelyAlignAtt = 0;
1145  int likelyWidthAtt = 0;
1146  if (atts[0] && (strcmp(atts[0], "ID")==0)) {
1147  mCurrentCSSID = atts[1];
1148  likelyWidthAtt = likelyAlignAtt = 2; // assumes ID always precedes other attributes
1149  }
1150  else
1151  mCurrentCSSID = "";
1152 
1153 
1154  if(atts[likelyAlignAtt] && (strcmp(atts[likelyAlignAtt], "align")==0)) {
1155  const int alignValueAtt = likelyAlignAtt+1;
1156  if(strcmp(atts[alignValueAtt], "centre")==0)
1157  mCurrentBlockAlign = oofRepBlock::alignCentre;
1158  else if(strcmp(atts[alignValueAtt], "right")==0)
1159  mCurrentBlockAlign = oofRepBlock::alignRight;
1160  else
1161  mCurrentBlockAlign = oofRepBlock::alignLeft;
1162 
1163  likelyWidthAtt +=2; // is after Align
1164  }
1165  else
1166  mCurrentBlockAlign = oofRepBlock::alignLeft; // default if not specified
1167 
1168  if(atts[likelyWidthAtt] && (strcmp(atts[likelyWidthAtt], "fixedWidth")==0)) {
1169  const int widthValueAtt = likelyWidthAtt+1;
1170  assert(atts[widthValueAtt]);
1171  sscanf(atts[widthValueAtt], "%d", &mCurrentBlockFixedWidth);
1172  }
1173  else
1174  mCurrentBlockFixedWidth = 0;
1175 
1176  mBuildState->set(eInBlock);
1177 }
1178 
1179 
1184 void
1185 OOF_XMLrepLayoutParser::AppendBandDependingOnState(oofRepBand* orphanedBand)
1186 {
1187  const int currentState = mBuildState->getRepBuildState();
1188 
1189  if (currentState & (eInFooterBreak|eInHeaderBreak)) // regardless of other states
1190  mCurrentBreakBand = orphanedBand;
1191  else {
1192  oofRepBandList* theBands = CurrentBandListDependingOnState();
1193  if (theBands)
1194  theBands->append(orphanedBand);
1195  else {
1196  assert(!"OOF_XMLrepLayoutParser::AppendBandDependingOnState called with unknown state"); //lint !e506 constant Boolean
1197  }
1198  }
1199 }
1200 
1201 
1203 OOF_XMLrepLayoutParser::CurrentBandListDependingOnState() const
1204 {
1205  const int maskedState = mBuildState->getRepBuildState() &
1207  |eInHeader|eInTable|eInFooter
1209  );
1210 
1211  oofRepBandList* ret;
1212  switch(maskedState){
1213  case eInFirstPageHeader:
1214  ret = &mReport->firstPageHeaders();
1215  break;
1216 
1217  case eInHeader:
1218  ret = &mReport->pageHeaders();
1219  break;
1220 
1221  case (eInHeader | eInTable): {
1222  oofRepViewBand* theViewBand = CurrentViewBand();
1223  ret = &theViewBand->headers();
1224  }
1225  break;
1226 
1227  case (eInFooter | eInTable): {
1228  oofRepViewBand*theViewBand = CurrentViewBand();
1229  ret = &theViewBand->footers();
1230  }
1231  break;
1232 
1233  case eInFirstPageFooter:
1234  ret = &mReport->firstPageFooters();
1235  break;
1236 
1237  case eInFooter:
1238  ret = &mReport->pageFooters();
1239  break;
1240 
1241  default:
1242  ret = 0;
1243  }
1244  return ret;
1245 }
1246 
1247 
1248 void
1249 OOF_XMLrepLayoutParser::BuildGraphBand(const char** atts)
1250 {
1251 // eg: <graph ID='1-1-1-1-1' type="bar" source="templateProgressData" height='400' graphWidth='400' graphHeight='246'/>
1252 
1253 // NASTY ASSUMPTIONS TO ATTRIBUTE ORDER, SO PROTECT THEM
1254  assert(atts[0] && atts[1] && (strcmp(atts[0], "ID")==0));
1255  assert(atts[2] && atts[3] && (strcmp(atts[2], "type")==0));
1256  assert(atts[4] && atts[5] && (strcmp(atts[4], "source")==0)); // also in GetDatabaseInContext below
1257  assert(atts[6] && atts[7] && (strcmp(atts[6], "height")==0));
1258  assert(atts[8] && atts[9] && (strcmp(atts[8], "graphWidth")==0));
1259  assert(atts[10] && atts[11] && (strcmp(atts[10], "graphHeight")==0));
1260  assert(atts[12] && atts[13] && (strcmp(atts[12], "title")==0));
1261 
1262  mCurrentCSSID = atts[1];
1263  const char* typeStr = atts[3];
1264  dbTable* theTable = GetDatabaseInContext(atts, 4); // cope with nested data in breaks, etc.
1265  assert(theTable); // otherwise <graph> refers to different DB schema
1266  dbView* adoptedView = theTable->makeView(); // assumption is that table represents the view we saved
1267 
1268  const int bandHeight = atoi(atts[7]);
1269  const int graphWidth = atoi(atts[9]);
1270  const int graphHeight = atoi(atts[11]);
1271  const oofString graphTitle = atts[13];
1272 
1273 // optional overlay attributes
1274  int numOverlaid = 0;
1275  dbView* overlayView = 0;
1276  if (atts[14] && atts[15] && (strcmp(atts[14], "numOverlaid")==0))
1277  numOverlaid = atoi(atts[15]);
1278  else if (atts[14] && atts[15] && (strcmp(atts[14], "overlaySource")==0)) {
1279 // has an overlay view with second database source
1280  dbTable* theTable = GetDatabaseInContext(atts, 14, "overlaySource");
1281  assert(theTable);
1282  overlayView = theTable->makeView();
1283  }
1284 
1285  oofGraph* orphanedGraph=0;
1286  if (strcmp(typeStr, "bar")==0) {
1287  orphanedGraph = new oofBarGraph(adoptedView);
1288  }
1289  else if (strcmp(typeStr, "column")==0) {
1290  orphanedGraph = new oofColumnGraph(adoptedView);
1291  }
1292  else if (strcmp(typeStr, "point")==0) {
1293  orphanedGraph = new oofPointGraph(adoptedView);
1294  }
1295  else if (strcmp(typeStr, "line")==0) {
1296  orphanedGraph = new oofLineGraph(adoptedView);
1297  }
1298  else if (strcmp(typeStr, "XY")==0) {
1299  orphanedGraph = new oofXYGraph(adoptedView);
1300  }
1301  else if (strcmp(typeStr, "stacked bar")==0) {
1302  oofStackedBarGraph* theBarGraph = new oofStackedBarGraph(adoptedView);
1303  if (numOverlaid)
1304  theBarGraph->setOverlaid(numOverlaid);
1305  else if (overlayView)
1306  theBarGraph->setOverlayView(overlayView); // currently copied
1307  orphanedGraph = theBarGraph;
1308  }
1309  else if (strcmp(typeStr, "ordinal stacked bar")==0) {
1310  oofOrdinalStackedBarGraph* theBarGraph = new oofOrdinalStackedBarGraph(adoptedView);
1311  if (numOverlaid)
1312  theBarGraph->setOverlaid(numOverlaid);
1313  else if (overlayView)
1314  theBarGraph->setOverlayView(overlayView); // currently copied
1315  orphanedGraph = theBarGraph;
1316  }
1317  else if (strcmp(typeStr, "pie")==0) {
1318  orphanedGraph = new oofPieGraph(adoptedView);
1319  }
1320  else
1322  oofString("Unknown graph type in OOF_XMLrepLayoutParser::BuildGraphBand: ", typeStr)
1323  );
1324 
1325  assert(orphanedGraph);
1326  orphanedGraph->setTitle(graphTitle);
1327  new oofPromisedGraphSettings(mCurrentCSSID, orphanedGraph); // self-deleting listener
1328  oofRepBand* adoptedBand = new oofRepGraphBand(orphanedGraph, bandHeight, graphHeight, graphWidth);
1329  if (!mCurrentCSSID.isEmpty())
1330  adoptedBand->ID(mCurrentCSSID);
1331  AppendBandDependingOnState(adoptedBand);
1332 
1333  delete overlayView; // overlay views currently cloned, not adopted but this will change!
1334 }
1335 
1336 
1337 void
1338 OOF_XMLrepLayoutParser::BuildSpaceBand(const char** atts)
1339 {
1340  mCurrentCSSID = "";
1341  int heightAtt;
1342  if (atts[2]==0)
1343  heightAtt = 1;
1344  else
1345  heightAtt = 3;
1346  assert(atts[heightAtt-1] && (strcmp(atts[heightAtt-1],"height")==0));
1347  const int spaceHeight = atoi(atts[heightAtt]);
1348 
1349  oofRepBand* adoptedBand = new oofRepSpaceBand(spaceHeight);
1350  if (!mCurrentCSSID.isEmpty())
1351  adoptedBand->ID(mCurrentCSSID);
1352  AppendBandDependingOnState(adoptedBand);
1353 }
1354 
1355 
1356 void
1357 OOF_XMLrepLayoutParser::BuildLineBand(const char** atts)
1358 {
1359  mCurrentCSSID = "";
1360  int heightAtt;
1361  if (atts[2]==0)
1362  heightAtt = 1;
1363  else
1364  heightAtt = 3;
1365  assert(atts[heightAtt-1] && (strcmp(atts[heightAtt-1],"height")==0));
1366  const int lineHeight = atoi(atts[heightAtt]);
1367 
1368  oofRepBand* adoptedBand = new oofRepLineBand(lineHeight);
1369  if (!mCurrentCSSID.isEmpty())
1370  adoptedBand->ID(mCurrentCSSID);
1371  AppendBandDependingOnState(adoptedBand);
1372 }
1373 
1374 
1375 void
1376 OOF_XMLrepLayoutParser::CloseTable()
1377 {
1378  const int currentLevel = mTablesStack.count()-1;//child
1379  const int kTopLevel = 0;
1380  if(currentLevel > kTopLevel){
1381  mBuildState->restoreOldState();
1382  const int currentState = mBuildState->getRepBuildState();
1383  oofRepBand* orphanedBand = mTablesStack.value(currentLevel);
1384  mTablesStack.deleteItem(currentLevel);
1385  if(currentState & (eInFooterBreak|eInHeaderBreak)){
1386  mCurrentBreakBand = orphanedBand;
1387  }
1388  else {
1389  oofRepViewBand* parentBand = CurrentViewBand();
1390  if(currentState & eInHeader){
1391  parentBand->headers() << orphanedBand;
1392  }
1393  else if(currentState & eInFooter){
1394  parentBand->footers() << orphanedBand;
1395  }
1396  else
1397  assert(!"Unknown nested state in OOF_XMLrepLayoutParser::CloseTable"); //lint !e506 constant Boolean
1398  }
1399  }
1400  else{ // at top
1401  oofRepViewBand* topViewBand = CurrentViewBand();
1402  mReport->body(topViewBand);
1403  mTablesStack.deleteItem(kTopLevel);
1404  mBuildState->clear(eInTable);
1405  }
1406 }//CloseTable
1407 
1408 
1409 void
1410 OOF_XMLrepLayoutParser::OpenLayout(const char** atts)
1411 {
1412  mBuildState->set(eInLayoutBand);
1413  mCurrentLayout = new oofRepLayoutBand;
1414  if (atts[0]) {
1415  assert(atts[0] && (strcmp(atts[0], "ID")==0));
1416  mCurrentCSSID = atts[1];
1417  mCurrentLayout->textStyle(new oofPromisedRepTextStyle(mCurrentCSSID));
1418  mCurrentLayout->ID(mCurrentCSSID);
1419  }
1420 }
1421 
1422 
1423 void
1424 OOF_XMLrepLayoutParser::CloseLayout()
1425 {
1426  AppendBandDependingOnState(mCurrentLayout);
1427  mCurrentLayout = NULL;
1428 }
1429 
1430 
1431 void
1432 OOF_XMLrepLayoutParser::OpenHeaderOrFooter(const char** atts, int firstState, int otherState)
1433 {
1434  int likelyKeepAt = 0;
1435  if(atts[0] && (strcmp(atts[1],"first")==0)) {
1436  mBuildState->set(firstState);
1437  likelyKeepAt = 2;
1438  }
1439  else
1440  mBuildState->set(otherState);// if not in table it's in page
1441 
1442  if(atts[likelyKeepAt] && (strcmp(atts[likelyKeepAt],"keepTogether")==0)) {
1443  const bool willKeep = dbBool::str2bool(atts[likelyKeepAt+1]);
1444  oofRepBandList* theBands = CurrentBandListDependingOnState();
1445  if (theBands)
1446  theBands->keepTogether(willKeep); // only record if not default of together
1447  }
1448 
1449 }
1450 
1451 
1452 // -------------------------------------------------------
1453 // O O F _ X M L r e p S t y l e P a r s e r
1454 // -------------------------------------------------------
1455 
1462 OOF_XMLrepStyleParser::OOF_XMLrepStyleParser(expatppNesting* parent, oofString& s) :
1463  expatppNesting(parent),
1464  mCallerString(s)
1465 {
1466  mCallerString = ""; // in case we get no content
1467 }
1468 
1469 
1470 // char Data call back
1471 void
1472 OOF_XMLrepStyleParser::charData(const XML_Char *s, int len)
1473 {
1474  if (emptyCharData(s, len))
1475  return;
1476  mCallerString.append(s,len); // multiple lines call charData multiple times
1477 }//end chardata
1478 
1479 
1480 // -------------------------------------------------------
1481 // O O F _ X M L r e p P a r s e r S t a t e
1482 // -------------------------------------------------------
1483 OOF_XMLrepParserState::OOF_XMLrepParserState():
1484 mRepGenState(0)
1485 {
1486 }
1487 
1488 void
1489 OOF_XMLrepParserState::saveOldState(bool clearNew)
1490 {
1491  mOldState.append(mRepGenState);
1492  if (clearNew)
1493  mRepGenState = 0;
1494 }
1495 
1496 
1497 void
1498 OOF_XMLrepParserState::restoreOldState()
1499 {
1500  const unsigned long numEntries = mOldState.count();
1501  assert(numEntries>0);
1502  const unsigned long currentPos = numEntries-1;
1503  mRepGenState = mOldState.value(currentPos);
1504  mOldState.deleteItem(currentPos);
1505 }
1506 
1507 
1508 // -------------------------------------------------------
1509 // o o f C S S 2 R e p T e x t S t y l e
1510 // -------------------------------------------------------
1511 void
1513 {
1514 //make a temp str and copy the block into it
1515 // this makes parseing easier - we can use strTok and strstr with no danger of them marcher of therought the whole
1516 // src string or wothout clobering thesrcString
1517  assert(!srcString.isEmpty());
1518  assert(srcString[0]=='{');
1519  oofString finder = srcString.subStringBetween('{', '}');
1520  mParseBuffer = finder.orphan(); // need a char string to avoid complaints in C routines
1521 
1522  const unsigned short fontSize = FindFontSize();
1523  inStyle->fontName( FindFontFamily() );
1524  inStyle->fontSize( fontSize );
1525  inStyle->leading( CalculateLeading(fontSize, FindLineHeight() ) );
1526  inStyle->fontStyle( MakeStyleNumber() );
1527  inStyle->color( FindFontColour() );
1528  inStyle->alignment( FindAlignment() );
1529  inStyle->finishConstruction();
1530 
1531  delete[] mParseBuffer;
1532 }
1533 
1534 
1535 oofString
1536 oofCSS2RepTextStyle::FindFontFamily()
1537 {
1538  oofString fontFamilyName;
1539  const char * fontStr = "font-family: ";
1540  const int kNameLen = 13; // sizeof("font-family: ")
1541  char *result;
1542  char theChar;
1543  int index=0;
1544  //Must zero string in case it's already been used
1545  fontFamilyName = "";
1546 
1547  //Find start of string "font-family: "
1548  //Set result = start of above string
1549  result = strstr(mParseBuffer,fontStr);
1550  if (result) {
1551  result +=kNameLen;
1552  theChar = result[index++];
1553  while(isprint(theChar)&&(theChar!=';')) // printingchars only
1554  {
1555  if(theChar != '\''){ //ignore quotes around font family names with spaces
1556  fontFamilyName += theChar;
1557  }
1558  theChar = result[index++];
1559 
1560  }
1561  return fontFamilyName;
1562  }
1563  else
1565 }//findFontFamily
1566 
1567 
1568 short
1569 oofCSS2RepTextStyle::FindFontSize()
1570 {
1571  const char* sizeStr = "font-size:";// CHECK SPCE ON END OF STRING
1572  char *result;
1573  int index=0;
1574  short fontSize;
1575 
1576  //Find start of string "font-size:r"
1577  //Set result = start of above string
1578  result = strstr(mParseBuffer,sizeStr);
1579  if (result) {
1580  result +=11;
1581  fontSize = atoi(result);
1582  return fontSize;
1583  }
1584  else
1586 }//fontsize
1587 
1588 
1589 float
1590 oofCSS2RepTextStyle::FindLineHeight()
1591 {
1592  const char* sizeStr = "line-height:";
1593  char *result;
1594  int index=0;
1595  float lineHeight=1.0;
1596 
1597  result = strstr(mParseBuffer,sizeStr);
1598  if(result){
1599  result += 13;
1600  lineHeight= atof(result);
1601  }
1602  return lineHeight;
1603 }//LineHeight
1604 
1605 
1606 short
1607 oofCSS2RepTextStyle::CalculateLeading(short fontSize,float lineHeight) const
1608 {
1609  return (lineHeight*fontSize)-fontSize;
1610 
1611 }//calculateLeading
1612 
1613 
1614 unsigned char
1615 oofCSS2RepTextStyle::MakeStyleNumber(){
1616  unsigned char styleNumber = 0;
1617 
1618  if (strstr(mParseBuffer,"font-weight: bold")){
1619  styleNumber = styleNumber|bold;
1620  }
1621  if(strstr(mParseBuffer,"font-style: italic")) {
1622  styleNumber = styleNumber|italic;
1623  }
1624  if (strstr(mParseBuffer,"text-decoration: underline")) {
1625  styleNumber = styleNumber|underline;
1626  }
1627  if (strstr(mParseBuffer,"text-shadow:")){
1628  styleNumber = styleNumber|shadow;
1629  }
1630  //if (strstr(mScratch,"stylenumber& outline")) {
1631  // cat to"text-shadow: 0.2em 0.2em :theStyleString
1632  //}
1633  if (strstr(mParseBuffer,"font-stretch: condensed)stylenumber& condense")) {
1634  styleNumber = styleNumber|condense;
1635  }
1636  if (strstr(mParseBuffer,"font-stretch: expanded)stylenumber& extend")) {
1637  styleNumber = styleNumber| extend;
1638  }
1639  return styleNumber;
1640 }
1641 
1642 
1643 oofColor
1644 oofCSS2RepTextStyle::FindFontColour()
1645 {
1646  unsigned int rgbArray[3];
1647  const char fontStr[] = "color: rgb(";
1648  const int kNameLen = sizeof(fontStr)-1; // subtract 1 for null
1649  char *result;
1650  int index=0;
1651 
1652  //Find start of string "color: rgb("
1653  //Set result = start of above string
1654  result = strstr(mParseBuffer,fontStr);
1655  if (result) {
1656  //jump over the string
1657  result +=kNameLen;
1658  sscanf(result,"%d,%d,%d",rgbArray,rgbArray+1,rgbArray+2);
1659  return oofColor(rgbArray[0],rgbArray[1],rgbArray[2]);
1660  }
1661  else
1663 }//findFontColour
1664 
1665 
1667 oofCSS2RepTextStyle::FindAlignment()
1668 {
1669  const char* fontStr = "text-align: "; // WARNING highly vulnerable parsing
1670  const int kNameLen = 12; // sizeof("text-align: ")
1671  const char* result;
1672  char theChar;
1673  unsigned long hashedIndex=0;
1675  //Find start of string "text-align: "
1676  //Set result = start of above string
1677  result = strstr(mParseBuffer,fontStr);
1678  if (result) {
1679  //jump over the string
1680  result += kNameLen;
1681  while(!isalpha(theChar = *result)) { // find the align string which follows text-align:
1682  result++;
1683  }
1684  while(isalpha(theChar = *result)) {
1685  hashedIndex += theChar;
1686  result++;
1687  }
1688  switch(hashedIndex){// as sums are unique for above strings
1689  case (int) 'l'+'e'+'f'+'t': // 427
1690  ret = oofColSizer::alignLeft;
1691  break;
1692  case (int) 'c'+'e'+'n'+'t'+'r'+'e': // 641
1694  break;
1695  case (int) 'r'+'i'+'g'+'h'+'t': //542
1697  break;
1698  case (int) 'j'+'u'+'s'+'t': // 782
1699  ret = oofColSizer::alignJust;
1700  break;
1701 
1702  default:
1703  ret = oofColSizer::alignLeft;
1704  break;
1705  }
1706  }
1707  else
1709  return ret;
1710 }
1711 
1712 
1713 // -------------------------------------------------------
1714 // o o f C S S 2 G r a p h S e t t i n g s
1715 // -------------------------------------------------------
1716 
1722 void
1724 {
1725  char* res;
1726  //make a temp str and copy the block into it
1727  // this makes parseing easier we can use strTok and strstr with no danger of them marcher of therought the whole
1728  // src string or wothout clobbering the srcString
1729  assert(!srcString.isEmpty());
1730  assert(srcString[0]=='{');
1731  oofString finder = srcString.subStringBetween('{', '}');
1732  char* parseBuffer = finder.orphan(); // need a char string to avoid complaints in C routines
1733 
1734  // not fast or smart might fix in future
1735  res = strstr(parseBuffer, "hasLegend:");
1736  if(res)
1737  theSettings->hasLegend(ParseBoolString(res));
1738 
1739  res = strstr(parseBuffer, "has3DEffect:");
1740  if(res)
1741  theSettings->has3DEffect(ParseBoolString(res));
1742 
1743  res = strstr(parseBuffer, "hasTitle:");
1744  if(res)
1745  theSettings->hasTitle(ParseBoolString(res));
1746 
1747  res = strstr(parseBuffer, "hasValuesOverColumns:");
1748  if(res)
1749  theSettings->hasValuesOverColumns(ParseBoolString(res));
1750 
1751  res = strstr(parseBuffer, "hasValuesNextToBars:");
1752  if(res)
1753  theSettings->hasValuesNextToBars(ParseBoolString(res));
1754 
1755  res = strstr(parseBuffer, "hasXLabel:");
1756  if(res)
1757  theSettings->hasXLabel(ParseBoolString(res));
1758 
1759  res = strstr(parseBuffer, "hasYLabel:");
1760  theSettings->hasYLabel(ParseBoolString(res));
1761 
1762  res = strstr(parseBuffer, "hasXAxisTicks:");
1763  if(res)
1764  theSettings->hasXAxisTicks(ParseBoolString(res));
1765 
1766 
1767  res = strstr(parseBuffer, "hasYAxisTicks:");
1768  if(res)
1769  theSettings->hasYAxisTicks(ParseBoolString(res));
1770 
1771 
1772  res = strstr(parseBuffer, "hasXTickLabels:");
1773  if(res)
1774  theSettings->hasXTickLabels(ParseBoolString(res));
1775 
1776 
1777  res = strstr(parseBuffer, "hasYTickLabels:");
1778  if(res)
1779  theSettings->hasYTickLabels(ParseBoolString(res));
1780 
1781  res = strstr(parseBuffer, "titlePos:");
1782  if(res)
1783  theSettings->titlePos(ParsePosString(res));
1784 
1785  res = strstr(parseBuffer, "XLabelPos:");
1786  if(res)
1787  theSettings->XLabelPos(ParsePosString(res));
1788 
1789  res = strstr(parseBuffer, "YLabelPos:");
1790  if(res)
1791  theSettings->YLabelPos(ParsePosString(res));
1792 
1793  res = strstr(parseBuffer, "the3DEffectMultiplier:");
1794  if(res){
1795  res += 22;
1796  theSettings->the3DEffectMultiplier(atof(res));
1797  }
1798 
1799  res = strstr(parseBuffer, "legendOffset:");
1800  if(res){
1801  res += 13;
1802  theSettings->legendOffset(atoi(res));
1803  }
1804 
1805  res = strstr(parseBuffer, "maxYLabelLen:");
1806  if(res){
1807  res += 13;
1808  theSettings->maxYLabelLen(atoi(res));
1809  }
1810  res = strstr(parseBuffer, "maxYTickLabelLen:");
1811  if(res){
1812  res += 17;
1813  theSettings->maxYTickLabelLen(atoi(res));
1814  }
1815  res = strstr(parseBuffer, "maxLegendLen:");
1816  if(res){
1817  res += 13;
1818  theSettings->maxLegendLen(atoi(res));
1819  }
1820  res = strstr(parseBuffer, "minorTickSize:");
1821  if(res){
1822  res += 14;
1823  theSettings->minorTickSize(atoi(res));
1824  }
1825  res = strstr(parseBuffer, "majorTickSize:");
1826  res += 14;
1827  theSettings->majorTickSize(atoi(res));
1828 
1829  res = strstr(parseBuffer, "YAxisHeight:");
1830  if(res){
1831  res += 12;
1832  theSettings->YAxisHeight(atoi(res));
1833  }
1834  res = strstr(parseBuffer, "intTickLabelMask:");
1835  if(res){
1836  res += 17;
1837  const oofString remainingStr = res;
1838  theSettings->intTickLabelMask(remainingStr.subStringBetween('\'', '\''));
1839  }
1840  res = strstr(parseBuffer, "realTickLabelMask:");
1841  if(res){
1842  res += 18;
1843  const oofString remainingStr = res;
1844  theSettings->realTickLabelMask(remainingStr.subStringBetween('\'', '\''));
1845  }
1846  delete[] parseBuffer;
1847 }
1848 
1849 
1850 bool
1851 oofCSS2GraphSettings::ParseBoolString(const char* searchStr)
1852 {
1853 // takes string of form "someTag: true ;... "
1854 // where .. implies further settings before null
1855 // and extracts the true or false setting
1856 
1857  char theChar;
1858  unsigned int sum=0;
1859  while(isalnum(theChar = *searchStr)) // skip "someTag"
1860  searchStr++;
1861  while(!isalpha(theChar = *searchStr)) // skip ": " to start of true/false
1862  searchStr++;
1863 
1864  const char truthValue = *searchStr; // just check first char
1865  const bool ret = dbBool::char2bool(truthValue); // cope with Y/N, 1/0, T/F etc.
1866  return ret;
1867 }
1868 
1869 
1871 oofCSS2GraphSettings::ParsePosString(const char* searchStr)
1872 {
1873  char theChar;
1874  unsigned int sum=0;
1875  while(isalpha(*searchStr))
1876  searchStr++;
1877  while(!isalpha(theChar = *searchStr))
1878  searchStr++;
1879  while(isalpha(theChar = *searchStr)){
1880  sum += theChar;
1881  searchStr++;
1882  }
1883  oofGeo::PositionState ret;
1884  switch(sum)
1885  {
1886  case (int) 'p'+'o'+'s'+'N'+'o'+'n'+'e': // 738:
1887  ret = oofGeo::posNone;
1888  break;
1889  case (int) 'p'+'o'+'s'+'T'+'o'+'p': // 645:
1890  ret = oofGeo::posTop;
1891  break;
1892  case (int) 'p'+'o'+'s'+'L'+'e'+'f'+'t': // 733:
1893  ret = oofGeo::posLeft;
1894  break;
1895  case (int) 'p'+'o'+'s'+'R'+'i'+'g'+'h'+'t': // 848:
1896  ret = oofGeo::posRight;
1897  break;
1898  case (int) 'p'+'o'+'s'+'B'+'o'+'t'+'t'+'o'+'m': // 851:
1899  ret = oofGeo::posBottom;
1900  break;
1901  case (int) 'p'+'o'+'s'+'B'+'e'+'l'+'o'+'w': // 843:
1902  ret = oofGeo::posBelow;
1903  break;
1904  case (int) 'p'+'o'+'s'+'T'+'o'+'L'+'e'+'f'+'t': // 928:
1905  ret = oofGeo::posToLeft;
1906  break;
1907  case (int) 'p'+'o'+'s'+'C'+'e'+'n'+'t'+'r'+'e': // 947:
1908  ret = oofGeo::posCentre;
1909  break;
1910  default:
1911  ret = oofGeo::posNone;
1912  }
1913  return ret;
1914 }
1915 
1916 
1917 
1918 
1919 
1920 
1921 
1922 // -------------------------------------------------------
1923 // o o f C S S 2 R e p o r t S e t t i n g s
1924 // -------------------------------------------------------
1925 
1926 void
1928 {
1929  // If we have a collision then we must just resort to an if(strcmp.. chain in following switch
1930  assert(!srcString.isEmpty());
1931  assert(srcString[0]=='{');
1932  oofString finder = srcString.subStringBetween('{', '}');
1933  char* parseBuffer = finder.orphan(); // need a char string to avoid complaints in C routines
1934 
1935  char *delims = "{:;}\\ ";//
1936  char *token;
1937  unsigned int HashResult;
1938  int value;
1939  // new better alg
1940  token = strtok( parseBuffer, delims );
1941  while ( token != NULL ) {
1942  HashResult = Hash(token);
1943  switch(HashResult){ // ordered as per oofRepSettings method decl
1944  case (int) 'r'+'p'+'L'+'i'+'n'+'e'+'T'+'h'+'i'+'c'+'k'+'n'+'e'+'s'+'s': // 1558
1945  token = strtok( NULL, delims );
1946  value = atoi(token);
1947  reportSettings->lineThickness(value);
1948  break;
1949 
1950  case (int) 'r'+'p'+'P'+'a'+'g'+'e'+'H'+'e'+'i'+'g'+'h'+'t': // 1208
1951  token = strtok( NULL, delims );
1952  reportSettings->pageHeight(atoi(token));
1953  break;
1954 
1955  case (int) 'r'+'p'+'P'+'a'+'g'+'e'+'W'+'i'+'d'+'t'+'h': // 1119
1956  token = strtok( NULL, delims );
1957  reportSettings->pageWidth(atoi(token));
1958  break;
1959 
1960  case (int) 'r'+'p'+'B'+'o'+'r'+'d'+'e'+'r'+'T'+'y'+'p'+'e': // 1250
1961  token = strtok( NULL, delims );
1962  reportSettings->borderType(atoi(token));
1963  break;
1964 
1965  case (int) 'r'+'p'+'B'+'a'+'n'+'d'+'I'+'n'+'d'+'e'+'n'+'t'+'i'+'n'+'g': // 1527
1966  token = strtok( NULL, delims );
1967  reportSettings->bandIndenting(atoi(token));
1968  break;
1969 
1970  case (int) 'r'+'p'+'L'+'e'+'f'+'t'+'M'+'a'+'r'+'g'+'i'+'n': // 1227
1971  token = strtok( NULL, delims );
1972  reportSettings->leftMargin(atoi(token));
1973  break;
1974 
1975  case (int) 'r'+'p'+'R'+'i'+'g'+'h'+'t'+'M'+'a'+'r'+'g'+'i'+'n': // 1342
1976  token = strtok( NULL, delims );
1977  reportSettings->rightMargin(atoi(token));
1978  break;
1979 
1980  case (int) 'r'+'p'+'T'+'o'+'p'+'M'+'a'+'r'+'g'+'i'+'n': // 1139
1981  token = strtok( NULL, delims );
1982  reportSettings->topMargin(atoi(token));
1983  break;
1984 
1985  case (int) 'r'+'p'+'B'+'o'+'t'+'t'+'o'+'m'+'M'+'a'+'r'+'g'+'i'+'n': // 1461
1986  token = strtok( NULL, delims );
1987  reportSettings->bottomMargin(atoi(token));
1988  break;
1989 
1990  case (int) 'r'+'p'+'C'+'o'+'l'+'S'+'e'+'p'+'W'+'i'+'d'+'t'+'h': // 1320
1991  token = strtok( NULL, delims );
1992  reportSettings->colSepWidth(atoi(token));
1993  break;
1994 
1995  case (int) 'r'+'p'+'B'+'l'+'o'+'c'+'k'+'V'+'e'+'r'+'t'+'S'+'e'+'p': // 1430
1996  token = strtok( NULL, delims );
1997  reportSettings->blockVertSep(atoi(token));
1998  break;
1999 
2000  case (int) 'r'+'p'+'D'+'e'+'f'+'a'+'u'+'l'+'t'+'T'+'e'+'x'+'t'+'S'+'t'+'y'+'l'+'e': // 1885
2001  token = strtok( NULL, delims );
2002  reportSettings->defaultTextStyle(new oofPromisedRepTextStyle(token));
2003  break;
2004 
2005 // defaultPageHeaders skipped - saved in <layout>
2006 // defaultPageFooters skipped
2007 
2008  case (int) 'r'+'p'+'D'+'r'+'a'+'w'+'H'+'e'+'a'+'d'+'i'+'n'+'g'+'s'+'D'+'o'+'w'+'n'+'T'+'o'+'L'+'e'+'v'+'e'+'l':
2009  token = strtok( NULL, delims );
2010  reportSettings->drawHeadingsDownToLevel(atoi(token));
2011  break;
2012 
2013  case (int) 'r'+'p'+'P'+'r'+'i'+'n'+'t'+'G'+'r'+'a'+'p'+'h'+'s'+'I'+'n'+'M'+'o'+'n'+'o': // 1956
2014  token = strtok( NULL, delims );
2015  if(strcmp(token,"true")==0)
2016  reportSettings->printGraphsInMono(true);
2017  else
2018  reportSettings->printGraphsInMono(false);
2019  break;
2020 
2021  case (int) 'r'+'p'+'M'+'o'+'d'+'a'+'l'+'P'+'r'+'e'+'v'+'i'+'e'+'w'+'W'+'i'+'n'+'d'+'o'+'w':
2022  token = strtok( NULL, delims );
2023  if(strcmp(token,"true")==0)
2024  reportSettings->modalPreviewWindow(true);
2025  else
2026  reportSettings->modalPreviewWindow(false);
2027  break;
2028 
2029  case (int) 'r'+'p'+'G'+'r'+'a'+'p'+'h'+'B'+'a'+'n'+'d'+'M'+'i'+'n'+'S'+'i'+'z'+'e'+'P'+'e'+'r'+'c'+'e'+'n'+'t':
2030  token = strtok( NULL, delims );
2031  reportSettings->graphBandMinSizePercent(atoi(token));
2032  break;
2033 
2034 // XMLsettings skipped - application code sets function pointer
2035  }//switch
2036  token = strtok( NULL, delims );
2037 
2038  }//while
2039  delete[] parseBuffer;
2040 }//ParseSettingsText
2041 
2042 
2043 unsigned long
2044 oofCSS2ReportSettings::Hash(const char* theStr)
2045 {
2046  int i =0;
2047  unsigned long res= 0;
2048  while(theStr[i] != NULL) {
2049  res += theStr[i++];
2050  }
2051  return res;
2052 }
2053 
2054 
2055 //-----------------------------------------
2056 // o o f R e p P r o m i s e C o m p l e t e r
2057 //-----------------------------------------
2058 const char*
2059 oofRepPromiseCompleter::findStringForID(const oofString& theID, const char* inString)
2060 {
2061  char* result;
2062  oofString searchPattern ="#"; // avoids id's emmbedded in css like rules
2063 
2064  if(*theID != '#')
2065  searchPattern += theID;
2066  else
2067  searchPattern = theID;
2068  const unsigned long searchLen = searchPattern.length();
2069 
2070  for (;;) { // loop until match only pattern - may match start of larger pattern
2071  result = strstr(inString,searchPattern); // could be "1-1-2" looking for "1-1"
2072  if (result==0)
2073  return 0; //**** FAILURE EXIT
2074 
2075  result += searchLen;
2076  const char charAfterPattern = *result;
2077  if ( (charAfterPattern=='-') ||
2078  (charAfterPattern=='_') ||
2079  isalnum(charAfterPattern)
2080  )
2081  inString = result; // adjust starting pos, matched substring so keep cycling
2082  else
2083  break; // not part of larger ID
2084  }
2085  // find the opening {
2086  while(*result!='{')
2087  result++;
2088  return result;
2089 
2090 }
2091 
2092 
2093 
2094 //--------------------------------------------------
2095 // o o f G r a p h S e t t i n g s C o m p l e t e r
2096 //---------------------------------------------------
2097 
2098 oofGraphSettingsCompleter* oofGraphSettingsCompleter::sCurrentlyConstructing;
2099 
2101  oofRepPromiseCompleter(inCSS)
2102 {
2103  sCurrentlyConstructing = this;
2104 }
2105 
2106 
2108 {
2109  sCurrentlyConstructing = 0;
2110 }
2111 
2112 
2113 void
2115 {
2116  broadcast(kCompletePromiseMsg, (unsigned long)this);
2117 }
2118 
2119 
2120 void
2122 {
2123  assert(inGraph);
2124  oofGraphSettings* inSettings = inGraph->getLocalSettings();
2125  const char* settingsStartAt = findStringForID(inID);
2126  if (settingsStartAt)
2127  oofCSS2GraphSettings::parseSettingsText(settingsStartAt, inSettings);
2128 }
2129 
2130 
2131 //----------------------------------------------------
2132 // o o f R e p T e x t S t y l e C o m p l e t er
2133 //----------------------------------------------------
2134 
2135 oofRepTextStyleCompleter* oofRepTextStyleCompleter::sCurrentlyConstructing;
2136 
2137 
2139  oofRepPromiseCompleter(inCSS)
2140 {
2141  sCurrentlyConstructing = this;
2142 }
2143 
2144 
2146 {
2147  sCurrentlyConstructing = 0;
2148 }
2149 
2150 
2151 void
2153 {
2154  const char* styleStartsAt = findStringForID(inStyle->ID());
2155  if (styleStartsAt) {
2156  oofCSS2RepTextStyle parser;
2157  parser.parseStyleText(styleStartsAt, inStyle);
2158  }
2159  // else will be caught by OOF_repXMLstyleCleanupVisitor
2160 }
2161 
2162 
2163 void
2165 {
2166  broadcast(kCompletePromiseMsg, (unsigned long)this);
2167 }
2168 
2169 
2170 
2171 //---------------------------------------------------
2172 // o o f P r o m i s e d R e p T e x t S t y l e
2173 //---------------------------------------------------
2176 {
2177  return new oofPromisedRepTextStyle(*this);
2178 }
2179 
2180 
2187 bool
2188 oofPromisedRepTextStyle::receiveMsg(OOFmsgT msg, unsigned long senderDefined)
2189 {
2190  if (msg==OOFmsg_BroadcasterClosing) {
2191  mListensTo = 0;
2192  // override parent because don't delete self
2193  }
2194  else {
2195  assert(msg==kCompletePromiseMsg);
2196  assert(sizeof(unsigned long)==sizeof(oofRepTextStyleCompleter*));
2197  oofRepTextStyleCompleter* completer = (oofRepTextStyleCompleter*) senderDefined; // safe downcast
2198  completer->completeStyle(this);
2199  }
2200  return true;
2201 }
2202 
2203 
2204 //---------------------------------------------------
2205 // o o f P r o m i s e d G r a p h S e t t i n g s
2206 //---------------------------------------------------
2213 bool
2214 oofPromisedGraphSettings::receiveMsg(OOFmsgT msg, unsigned long senderDefined)
2215 {
2216  if(msg==kCompletePromiseMsg) {
2217  assert(sizeof(unsigned long)==sizeof(oofGraphSettingsCompleter*));
2218  oofGraphSettingsCompleter* completer = (oofGraphSettingsCompleter*) senderDefined; // safe downcast
2219  completer->completeSettings(mID, mGraph);
2220  }
2221  else
2222  oofSingleListener::receiveMsg(msg, senderDefined);
2223  return true;
2224 }
2225 
2226 
2227 // -------------------------------------------------------
2228 // O O F _ X M L r e p A d o r n e r P a r s e r
2229 // -------------------------------------------------------
2230 OOF_XMLrepAdornerParser::OOF_XMLrepAdornerParser(expatppNesting* parent, OOF_Dictionary& callerDict) :
2231  expatppNesting(parent),
2232  mCallerDict(callerDict)
2233 {
2234 }
2235 
2236 
2237 void
2238 OOF_XMLrepAdornerParser::startElement(const char* name, const char** atts)
2239 {
2240  assert(strcmp(name,"adorner")==0); // only tags we should see are adorners
2241  assert(atts[0] && atts[1] && (strcmp(atts[0], "parentID")==0));
2242  mCurrentID = atts[1];
2243  mCurrentSerializable = 0;
2244  oofXMLserializableParser* theParser = new oofXMLserializableParser(this, &mCurrentSerializable); // self-deleting sub parser
2245 }
2246 
2247 
2248 void
2250 {
2251  // this is after return from sub-parser
2252  assert(strcmp(name,"adorner")==0); // only tags we should see are adorners
2253  if (!mCurrentSerializable)
2254  return; // user code had unknown serializable
2255 
2256  oofAdorner* adoptedAdorner = dynamic_cast<oofAdorner*>(mCurrentSerializable);
2257  assert(adoptedAdorner);
2258  OOF_adornerHolder* existingHolder = (OOF_adornerHolder*)mCallerDict[mCurrentID]; // safe downcast
2259  if (existingHolder)
2260  existingHolder->adorners() << adoptedAdorner;
2261  else {
2262  OOF_adornerHolder* adoptedHolder = new OOF_adornerHolder(mCurrentID, adoptedAdorner);
2263  mCallerDict.append(adoptedHolder);
2264  }
2265 }
2266 
2267 
2268 #endif // entire file conditional on OOF_RW_READ_REPORTS
unsigned short drawHeadingsDownToLevel() const
Definition: oofrep3.cpp:515
void setFixedWidth(unsigned short colNum, unsigned long)
Definition: oofsize.cpp:228
oofRepBreakList & footerBreaks()
Definition: oofrep.h:2124
void colSizer(oofColSizer *adoptedSizer)
Definition: oofsize.cpp:71
oofPromisedRepTextStyle(const oofString &theID)
Definition: oofriXML.cpp:192
bool hasYAxisTicks() const
Definition: oofSting.cpp:317
Parse an tag for serialized adorners.
Definition: oofriXML.h:109
Graph of oofGeoPoint arbitrary points from XY data, no assumptions of order.
Definition: oofGrphs.h:234
bool invariant() const
true after full initialisation
Definition: oofrep.h:2633
unsigned char fontStyle() const
Definition: oofrep.h:2556
virtual void endElem_style()
Definition: oofriXML.cpp:665
dbConnect * mDB
Definition: oofriXML.h:75
simple visitor to remove ID's for anything without text style matched to it.
Definition: oofriXML.cpp:265
static void raise(std::ostream &, bool terminateAfterMsg=true)
Circular graph of oofGeoSector wedge-like pieces.
Definition: oofGrphs.h:325
dbTable * table(unsigned int) const
Definition: oof1.cpp:436
short leading() const
Definition: oofrep.h:2563
virtual void endUnknownElem(const char *name)
Definition: oofriXML.cpp:697
oofRepBandList & firstPageHeaders()
Definition: oofrep.h:1887
virtual void startElement(const XML_Char *name, const XML_Char **atts)
Definition: oofriXML.cpp:2238
oofRepBandList & footers()
Definition: oofrep.h:2141
bool hasLegend() const
Definition: oofSting.cpp:203
void adopt(oofAdornerList &)
Definition: oofadorn.cpp:71
oofRepBreakList & headerBreaks()
Definition: oofrep.h:2117
bool modalPreviewWindow() const
Definition: oofrep3.cpp:555
virtual dbView * view(unsigned short whichView=0) const
Request a dbView which may be the source of data for the item.
Definition: oofrep2.cpp:272
static oofGraphSettingsCompleter * currentlyConstructing()
Definition: oofriXML.cpp:126
Abstract base for anything drawn on report.
Definition: oofrep.h:860
Graph of oofGeoBar horizontal bars where each series is percentage of one bar, all same length...
Definition: oofGrphs.h:305
Force break to a new page for each record drawn by oofRepViewBand.
Definition: oofrep.h:1630
oofRepBandList & pageFooters()
Definition: oofrep.h:1881
oofRep * mReport
owned - the current report being built, may actually be oofRepSection
Definition: oofriXML.h:73
oofGeo::PositionState XLabelPos() const
Definition: oofSting.cpp:434
static oofRepTextStyleCompleter * currentlyConstructing()
Definition: oofriXML.cpp:149
static bool char2bool(char)
Definition: oof4.cpp:1221
virtual void startUnknownElem(const char *name, const char **atts)
Definition: oofriXML.cpp:581
Used by OOF_XMLrepParser::FinishReport to match graph settings with ID.
Definition: oofriXML.cpp:118
Graph of oofGeoBar horizontal bars where each point in series is percentage of one bar...
Definition: oofGrphs.h:282
unsigned short borderType() const
Definition: oofrep3.cpp:308
virtual void endElem_schema()
Definition: oofriXML.cpp:686
oofRepPromiseCompleter(const oofString &inCSS)
Definition: oofriXML.cpp:96
Graph of oofGeoBar horizontal bars.
Definition: oofGrphs.h:259
virtual void endElement(const XML_Char *name)
Definition: oofriXML.cpp:2249
Report that contains list of unrelated other reports as oofRepSection's.
Definition: oofrep.h:677
oofRepCustomViewDrawer * customDrawer(unsigned short col)
Definition: oofrep2.cpp:172
virtual bool receiveMsg(OOFmsgT msg, unsigned long senderDefined)
Receive broadcast from oofGraphSettingsCompleter::completePromises to get settings.
Definition: oofriXML.cpp:2188
Settings object for overriding behaviours of an instance of oofGraph.
Definition: oofSting.h:24
void deleteAll()
Definition: oof2.cpp:433
void append(const char *, unsigned long appendLen)
Definition: oofstr.cpp:843
char * orphan(bool neverReturnNil=true)
Give away our internal buffer, clearing our length and pointer.
Definition: oofstr.cpp:2339
Base object for class that broadcasts messages to OOF_mixPromise instances.
Definition: oofriXML.cpp:93
unsigned short minorTickSize() const
Definition: oofSting.cpp:534
Graph of oofGeoColumn vertical bars.
Definition: oofGrphs.h:163
unsigned long count() const
Definition: oofarray.h:126
Parse a