public enum Orientation { portrait, landscape };
+public enum PageFormat { custom, letter, legal, ledger };
+
public enum RenderAction { addPage, closePage, levelStart, levelFinish, groupStart, groupFinish, actualRows };
static class PleaseWait : Window
Label { this, foreground = black, anchor = { top = 4 }, labeledWindow = this };
}
+static define dpi = 100;
class PreviewPage : Window
{
background = dimGray;
- //size = { 850 + shadowS + pgs * 2, 1100 + shadowS + pgs * 2 };
- public property Orientation orientation
+ public property Page page
{
set
{
- if(value == portrait)
- size = { 850 + shadowS + pgs * 2, 1100 + shadowS + pgs * 2 };
- else if(value == landscape)
- size = { 1100 + shadowS + pgs * 2, 850 + shadowS + pgs * 2 };
- orientation = value;
+ page = value;
+ if(page && page.report)
+ {
+ switch(page.report.pageFormat)
+ {
+ case letter:
+ if(page.report.orientation == landscape)
+ size = { 11*dpi + shadowS + pgs * 2, 8.5*dpi + shadowS + pgs * 2 };
+ else
+ size = { 8.5*dpi + shadowS + pgs * 2, 11*dpi + shadowS + pgs * 2 };
+ break;
+ case legal:
+ if(page.report.orientation == landscape)
+ size = { 14*dpi + shadowS + pgs * 2, 8.5*dpi + shadowS + pgs * 2 };
+ else
+ size = { 8.5*dpi + shadowS + pgs * 2, 14*dpi + shadowS + pgs * 2 };
+ break;
+ case ledger:
+ if(page.report.orientation == landscape)
+ size = { 17*dpi + shadowS + pgs * 2, 11*dpi + shadowS + pgs * 2 };
+ else
+ size = { 11*dpi + shadowS + pgs * 2, 17*dpi + shadowS + pgs * 2 };
+ break;
+ case custom:
+ if(page.report.orientation == landscape && page.report.pageSize.w > page.report.pageSize.h)
+ size = { page.report.pageSize.w + shadowS + pgs * 2, page.report.pageSize.h + shadowS + pgs * 2 };
+ else
+ size = { page.report.pageSize.h + shadowS + pgs * 2, page.report.pageSize.w + shadowS + pgs * 2 };
+ break;
+ }
+ }
}
}
- Orientation orientation;
-
Page page;
void OnRedraw(Surface surface)
public class Page : Window
{
background = white;
- //size = { 612, 792 };
- public property Orientation orientation
+public:
+ property Report report
{
set
{
- if(value == portrait)
+ report = value;
+ if(report)
{
- size = { 850, 1100 };
- inside.size = { 850, 1100 };
+ size = report.pageSize;
+ inside.size = report.pageSize;
}
- else if(value == landscape)
- {
- size = { 1100, 850 };
- inside.size = { 1100, 850 };
- }
- orientation = value;
}
+ get { return report; }
}
- Orientation orientation;
-
- public PageInside inside { this }; // , size = { 612, 792 }
- public int headerHeight;
-
-}
+ Window inside { this };
-public class PageInside : Window
-{
- public OldList details;
+ int headerHeight;
- ~PageInside()
- {
- details.Free(null);
- }
+private:
+ Report report;
}
public class ReportRender
{
- public virtual void Render(ReportDestination destination, Report report);
- public virtual int GetPageNumber();
+public:
+ virtual void Render(ReportDestination destination, Report report);
+ virtual int GetPageNumber();
}
static ReportRenderNormal ersCurrentReport;
}
}
-public class ReportRenderNormal : ReportRender
+public void ERSProgressAdvance()
{
- OldList pages;
-
- ~ReportRender()
+ if(!ersNumRows) ersNumRows++;
+ ersNumRows++;
+ ersNumRows = Min(ersNumRows, pleaseWait.progress.range);
+ pleaseWait.progress.progress = ersNumRows;
+ if(ersNumRows == pleaseWait.progress.range || !(ersNumRows%100))
{
- pages.Free(null);
+ ((GuiApplication)__thisModule.application).ProcessInput(true);
+ pleaseWait.UpdateDisplay();
}
+}
+public class ReportRenderNormal : ReportRender
+{
public:
int pageNumber;
renderAction = levelStart;
ersCurrentReport = this;
ersNumRows = 0;
- if(!report.groupings._[0].filtered)
+ if(!report.groupings[0].filtered)
{
pleaseWait.master = destination.master;
pleaseWait.Create();
- pleaseWait.progress.range = report.groupings._[0].row.tbl.rowsCount;
+
+ pleaseWait.progress.range = report.groupings[0].rowsCount ? report.groupings[0].rowsCount : report.groupings[0].row.rowsCount;
pleaseWait.progress.progress = 0;
((GuiApplication)__thisModule.application).ProcessInput(true);
pleaseWait.UpdateDisplay();
}
- for(pageNumber = 1; true; pageNumber++)
+ for(pageNumber = 1; ; pageNumber++)
{
- page = Page { orientation = report.orientation };
+ Detail lastDetail = null;
+ page = Page { report = report };
destination.AddPage(page);
inside = page.inside;
- inside.anchor = report.insideMarginAnchor;
+ inside.anchor = Anchor { left = report.insideMarginAnchor.left.distance, top = report.insideMarginAnchor.top.distance,
+ right = report.insideMarginAnchor.right.distance, bottom = report.insideMarginAnchor.bottom.distance };
insideSize = inside.size.h;
pageTop = 0;
if(report.reportHeader)
{
reportHeader = eInstance_New(report.reportHeader);
+ reportHeader.anchor = Anchor { left = 0, top = 0, right = 0 };
reportHeader.master = destination;
reportHeader.parent = inside;
- reportHeader.anchor = Anchor { left = 0, top = 0, right = 0 };
-
+
pageTop += reportHeader.size.h;
- //inside.details.Add(OldLink { data = reportHeader });
reportHeader.Create();
-
+
}
/*if(report.reportFooter)
{
reportFooter = eInstance_New(report.reportFooter);
+ reportFooter.anchor = Anchor { left = 0, bottom = 0, right = 0 };
reportFooter.master = destination;
reportFooter.parent = inside;
- reportFooter.anchor = Anchor { left = 0, bottom = 0, right = 0 };
reportFooter.Create();
}*/
}
if(report.pageHeader)
{
pageHeader = eInstance_New(report.pageHeader);
+ pageHeader.anchor = Anchor { left = 0, top = pageTop, right = 0 };
pageHeader.master = destination;
pageHeader.parent = inside;
- pageHeader.anchor = Anchor { left = 0, top = pageTop, right = 0 };
-
+
pageTop += pageHeader.size.h;
- //inside.details.Add(OldLink { data = pageHeader });
pageHeader.Create();
}
-
+
if(report.pageFooter)
{
pageFooter = eInstance_New(report.pageFooter);
else
footerHeight = 0;
- if(report.rowDetail)
+ if(report.rowDetail || (renderAction == levelFinish && level > 0) || renderAction == groupFinish)
{
bool loop;
//int levelHead = 0;
int c;
for(c = 0; c < ((renderAction == groupStart) ? level : (level + 1)); c++)
{
- if(report.groupings._[c].continuation)
- AddDetailToPage(destination, eInstance_New(report.groupings._[c].continuation));
+ if(report.groupings[c].continuation)
+ {
+ Detail continuation = eInstance_New(report.groupings[c].continuation);
+ continuation.level = c;
+ AddDetailToPage(destination, continuation);
+ }
}
}
{
// end of rows, end of last group, end of report
// TESTING THIS HERE... (UNCOMMENTED AND ADDED CHECK FOR size == 1)
- if(report.groupings.size == 1 && report.groupings._[level].footer)
+ if(report.groupings.size == 1 && report.groupings[level].footer)
{
- if(AddDetailToPage(destination, eInstance_New(report.groupings._[level].footer)))
+ Detail groupFooter = eInstance_New(report.groupings[level].footer);
+ groupFooter.level = level;
+ if(AddDetailToPage(destination, groupFooter))
{
//dontAdvance = true;
loop = false;
}
break;
case groupStart:
- if(report.Advance(report.groupings._[level], level ? report.groupings._[level - 1].groupId : 0, &dontAdvance))
+ lastDetail = null;
+ if(report.Advance(report.groupings[level], level ? report.groupings[level - 1].groupId : 0, &dontAdvance))
{
report.ExecuteRowData(level);
- if(report.groupings._[level].header)
+ if(report.groupings[level].header)
{
- Detail groupStart = eInstance_New(report.groupings._[level].header);
+ Detail groupStart = eInstance_New(report.groupings[level].header);
+ groupStart.level = level;
+
if(AddDetailToPage(destination, groupStart))
{
dontAdvance = true;
}
break;
case groupFinish:
- if(report.groupings._[level].footer)
+ if(lastDetail)
+ lastDetail.isLast = true;
+ if(report.groupings[level].footer)
{
- Detail groupEnd = eInstance_New(report.groupings._[level].footer);
+ Detail groupEnd = eInstance_New(report.groupings[level].footer);
+ int hh = (insideSize - pageTop - footerHeight) - groupEnd.size.h;
+ groupEnd.level = level;
if(AddDetailToPage(destination, groupEnd))
{
//dontAdvance = true;
loop = false;
break;
}
- else if(overlap - groupEnd.size.h < 0)
+ else if(hh < 0) // Use the value before calling AddDetailToPage()
{
overlap = 0;
groupEnd.Destroy(0);
renderAction = groupStart;
break;
case actualRows:
- if(report.Advance(report.groupings._[level], level ? report.groupings._[level - 1].groupId : 0, &dontAdvance))
+ if(report.Advance(report.groupings[level], level ? report.groupings[level - 1].groupId : 0, &dontAdvance))
{
- if(AddDetailToPage(destination, eInstance_New(report.rowDetail)))
+ Detail detail;
+ if(AddDetailToPage(destination, (detail = eInstance_New(report.rowDetail))))
{
dontAdvance = true;
loop = false;
break;
}
else
+ {
report.ExecuteRowData(level);
+ lastDetail = detail;
+ }
}
else
{
}
}
- nil = report.nil;
+ nil = report.nil && renderAction != groupFinish && (renderAction != levelFinish || level == 0);
}
else
{
nil = true;
}
+ // Cancel group headers if we didn't have space to display any row
+ if(!lastDetail)
+ {
+ Detail detail, prev;
+ for(detail = (Detail)inside.lastChild; detail; detail = prev)
+ {
+ prev = (Detail)detail.previous;
+ if(level > 0 && detail._class == report.groupings[level-1].header)
+ {
+ detail.Destroy(0);
+ level--;
+ renderAction = groupStart;
+ }
+ else
+ {
+ if(detail._class == report.groupings[level].footer);
+ else
+ lastDetail = detail;
+ break;
+ }
+ }
+ }
+ if(lastDetail)
+ lastDetail.isLast = true;
+
if(nil && report.reportFooter)
{
reportFooter = eInstance_New(report.reportFooter);
pageFooter.anchor = Anchor { left = 0, bottom = (int)reportFooter.size.h, right = 0 };
else
pageFooter.anchor = Anchor { left = 0, bottom = 0, right = 0 };
-
- //inside.details.Add(OldLink { data = pageFooter });
+
pageFooter.Create();
}
if(nil && report.reportFooter)
{
- //inside.details.Add(OldLink { data = reportFooter });
reportFooter.Create();
}
- pages.Add(OldLink { data = page });
-
destination.EndPage(page);
if(nil)
break;
-
+
// still have to bump report footer if it does not fit...
}
pleaseWait.Destroy(0);
RenderAction renderAction;
Page page;
- PageInside inside;
+ Window inside;
Detail reportHeader;
Detail reportFooter;
{
int detailSize;
+ detail.anchor = Anchor { left = 0, right = 0 };
detail.master = destination;
detail.parent = inside;
detailSize = detail.size.h;
overlap = (insideSize - pageTop - footerHeight) - detailSize;
-
+
if(overlap < 0 && detail.keepTogether)
{
delete detail;
{
detail.anchor = Anchor { left = 0, top = pageTop, right = 0 };
pageTop += detailSize;
- //inside.details.Add(OldLink { data = detail });
detail.Create();
// This will probably never go here... (Only report/page headers have keepTogether set to false)
- if(overlap < 0)
- return true;
+ /*if(overlap < 0)
+ {
+ printf("bug");
+ }*/
+
}
return false;
}
public class ReportDestination : Window
{
-
- int pageCount;
-
- OldList pages;
public:
- Report report;
+ public property Report report { watchable set { report = value; } get { return report; } }
virtual void EndPage(Page page)
{
SetScrollPosition((page.master.size.w - clientSize.w) / 2, 0);
}
- virtual void AddPage(Page page)
- {
- }
-
- virtual Report GetReport()
- {
- return null;
- }
-
+ virtual void AddPage(Page page);
+ virtual Report GetReport() { return null; }
private:
- ~ReportDestination()
- {
- pages.Free(null);
- }
+ Report report;
+ int pageCount;
+
+ List<PreviewPage> pages { };
}
public class PrintedReport : ReportDestination
{
displayDriver = "Win32Printer";
+ fullRender = true;
Page lastPage;
return ReportDestination::OnCreate();
}
+ watch(report)
+ {
+ size = report.pageSize;
+ };
+
void AddPage(Page page)
{
if(pageCount && display)
display.NextPage();
lastPage = page;
+ page.anchor = { left = 0, top = 0, right = 0, bottom = 0};
page.master = this;
page.parent = this;
- page.anchor = { left = 0, top = 0, right = 0, bottom = 0};
pageCount++;
page.Create();
}
void AddPage(Page page)
{
- PreviewPage previewPage { this, this, page = page, orientation = page.orientation,
- anchor = { top = pageCount * ((int)page.size.h + shadowS + pgs) } };
+ PreviewPage previewPage { this, this, page = page, anchor = { top = pageCount * ((int)page.size.h + shadowS + pgs) } };
previewPage.Create();
+ page.anchor = { left = pgs, top = pgs, right = shadowS + pgs, bottom = shadowS + pgs};
page.master = previewPage;
page.parent = previewPage;
- page.anchor = { left = pgs, top = pgs, right = shadowS + pgs, bottom = shadowS + pgs};
- pages.Add(OldLink { data = previewPage });
page.Create();
pageCount++;
}
-
+
Report GetReport()
{
return report;
void OnResize(int width, int height)
{
- SetScrollPosition((scrollArea.w - width) / 2, scroll.y);
- }
-
- ~ReportPreviewArea()
- {
+ scroll = { (scrollArea.w - width) / 2, scroll.y };
}
}
Array<FileFilter> csvFilters
{ [
- {
+ {
$"Comma Separated Values Spreadsheet (*.csv)",
"csv"
},
hasVertScroll = true;
dontHideScroll = true;
background = dimGray;
-
+
Page lastPage;
void AddPage(Page page)
{
- int h;
if(pageCount && display)
display.NextPage();
lastPage = page;
page.master = this;
page.parent = this;
page.size = { MAXINT - 10, MAXINT - 10 };
- h = page.size.h;
pageCount++;
page.Create();
}
-
- void PutString(File f, char * text)
+
+ void PutString(File f, const char * text)
{
char output[4096];
int s = 0, d = 0;
{
char filePath[MAX_LOCATION];
strcpy(filePath, report.title);
+ ChangeChars(filePath, "/\\:*?\"|<>", '_');
strcat(filePath, ".csv");
saveTo.master = master;
saveTo.filePath = filePath;
File f = FileOpen(saveTo.filePath, write);
if(f)
{
- Detail detail, first = null;
+ Detail detail, first = null;
for(detail = (Detail)page.inside.firstChild; detail && detail != first; detail = (Detail)detail.next)
{
if(!first) first = detail;
if(eClass_IsDerived(detail._class, class(Detail)))
{
Label label, first = null;
-
+
if(detail._class == report.pageFooter) continue;
- if(detail._class == report.groupings._[0].header)
+ if(detail._class == report.groupings[0].header)
f.Puts("\n");
for(label = (Label)detail.firstChild; label && label != first; label = (Label)label.next)
{
if(!first) first = label;
if(label._class == class(ReportTitle) || eClass_IsDerived(label._class, class(Label)))
{
- char * text = label.text;
+ const char * text = label.text;
if(label != first)f.Puts(",");
if(text)
PutString(f, text);
}
}
- if(detail._class == report.groupings._[0].header)
+ if(detail._class == report.groupings[0].header)
f.Puts("\n");
f.Puts("\n");
}
public:
Id id;
Field field;
-
+
bool RowMatch(Row row)
{
Id value;
}
}
-public class ArrayIdFilters : OldArray
-{
- type = class(IdFilter);
-public:
- IdFilter * const _;
-}
-
public class Grouping
{
public:
Row row;
Field field, fieldLink;
bool filtered;
- ArrayIdFilters filters { };
+ Array<IdFilter> filters { };
// Contractors have a list of trades they're in
Field listFieldLink;
bool activeOnly;
Field activeField;
+ uint rowsCount;
subclass(Detail) header;
subclass(Detail) continuation;
~Grouping()
{
+ filters.Free();
delete row;
}
-
+
virtual bool ShouldSkip()
{
return false;
result = row.Next();
if(!result)
return false;
-
+
if(reverseLink)
reverseLink.row.GetData(reverseListFieldLink, reverseIdList);
if(result && filtered && filters.size)
{
int f;
- for(f = 0; f < filters.size && result && filters._[f].field; f++)
+ for(f = 0; f < filters.size && result && filters[f].field; f++)
{
Id id = 0;
- row.GetData(filters._[f].field, id);
- if(id != filters._[f].id)
+ row.GetData(filters[f].field, id);
+ if(id != filters[f].id)
{
result = false;
break;
}
}
-public class ArrayGroupings : OldArray
-{
- type = class(Grouping);
-public:
- Grouping * const _;
-}
-
public class Report
{
public:
- Orientation orientation;
+ public property Orientation orientation { set { orientation = value; UpdateSize(); } get { return orientation; } }
+ public property PageFormat pageFormat { set { pageFormat = value; UpdateSize(); } get { return pageFormat; } }
+
+ Size pageSize;
Anchor insideMarginAnchor;
- ArrayGroupings groupings { };
+ Array<Grouping> groupings { };
- property String title
+ property const String title
{
set
{
{
return grouping.Advance(linkId, dontAdvance);
}
-
+
virtual bool ExecuteData(Database db)
{
return false;
}
- virtual void ExecuteRowData(int group)
- {
- }
+ virtual void ExecuteRowData(int group);
+ virtual void OnReset();
property bool nil
{
get
{
- if(groupings && groupings.size && groupings._[0].row)
- return groupings._[0].row.nil;
+ if(groupings && groupings.size && groupings[0].row)
+ return groupings[0].row.nil;
return true;
}
}
-private:
+private:
+ Orientation orientation;
+ PageFormat pageFormat;
+
+ void UpdateSize()
+ {
+ switch(pageFormat)
+ {
+ case letter:
+ if(orientation == landscape)
+ pageSize = { 11*dpi, 8.5*dpi };
+ else
+ pageSize = { 8.5*dpi, 11*dpi };
+ break;
+ case legal:
+ if(orientation == landscape)
+ pageSize = { 14*dpi, 8.5*dpi };
+ else
+ pageSize = { 8.5*dpi, 14*dpi };
+ break;
+ case ledger:
+ if(orientation == landscape)
+ pageSize = { 17*dpi, 11*dpi };
+ else
+ pageSize = { 11*dpi, 17*dpi };
+ break;
+ }
+ }
+
+ Report()
+ {
+ property::pageFormat = letter;
+ }
+
~Report()
{
- /*int c;
- for(c = 0; c<groupings.size; c++)
- delete groupings._[c];*/
+ groupings.Free();
delete title;
delete render;
}
{
public:
bool keepTogether;
+ bool isLast;
+ int level;
subclass(Detail) rowDetail;
}