ecere: Added ChangeChars(); eda/ers: ; Avoiding bad filenames
[sdk] / eda / libeda / src / ers.ec
index 4d42772..878925f 100644 (file)
@@ -5,6 +5,8 @@ define margin = 36;
 
 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
@@ -30,24 +32,48 @@ public class ReportTitle : 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)
@@ -70,36 +96,34 @@ public class Page : Window
 {
    background = white;
 
-   Orientation orientation;
 public:
-   property Orientation orientation
+   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; }
    }
 
    Window inside { this };
 
    int headerHeight;
-   
+
+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;
@@ -117,6 +141,19 @@ public void ERSProgressAdvanceLevelCheck()
    }
 }
 
+public void ERSProgressAdvance()
+{
+   if(!ersNumRows) ersNumRows++;
+   ersNumRows++;
+   ersNumRows = Min(ersNumRows, pleaseWait.progress.range);
+   pleaseWait.progress.progress = ersNumRows;
+   if(ersNumRows == pleaseWait.progress.range || !(ersNumRows%100))
+   {
+      ((GuiApplication)__thisModule.application).ProcessInput(true);
+      pleaseWait.UpdateDisplay();
+   }
+}
+
 public class ReportRenderNormal : ReportRender
 {
 public:
@@ -124,7 +161,6 @@ public:
 
    void Render(ReportDestination destination, Report report)
    {
-      Detail lastDetail = null;
       bool dontAdvance = false;
       bool nil;
       level = 0;
@@ -136,17 +172,20 @@ public:
       {
          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;
@@ -155,20 +194,20 @@ public:
             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;
                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();
             }*/
          }
@@ -176,15 +215,15 @@ public:
          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;
 
             pageHeader.Create();
          }
-         
+
          if(report.pageFooter)
          {
             pageFooter = eInstance_New(report.pageFooter);
@@ -195,7 +234,7 @@ public:
          else
             footerHeight = 0;
 
-         if(report.rowDetail)
+         if(report.rowDetail || (renderAction == levelFinish && level > 0) || renderAction == groupFinish)
          {
             bool loop;
             //int levelHead = 0;
@@ -209,9 +248,9 @@ public:
                {
                   if(report.groupings[c].continuation)
                   {
-                     if(lastDetail)
-                        lastDetail.isLast = true;
-                     AddDetailToPage(destination, eInstance_New(report.groupings[c].continuation));
+                     Detail continuation = eInstance_New(report.groupings[c].continuation);
+                     continuation.level = c;
+                     AddDetailToPage(destination, continuation);
                   }
                }
             }
@@ -234,7 +273,9 @@ public:
                         // TESTING THIS HERE... (UNCOMMENTED AND ADDED CHECK FOR size == 1)
                         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;
@@ -251,12 +292,15 @@ public:
                      }
                      break;
                   case groupStart:
+                     lastDetail = null;
                      if(report.Advance(report.groupings[level], level ? report.groupings[level - 1].groupId : 0, &dontAdvance))
                      {
                         report.ExecuteRowData(level);
                         if(report.groupings[level].header)
                         {
                            Detail groupStart = eInstance_New(report.groupings[level].header);
+                           groupStart.level = level;
+
                            if(AddDetailToPage(destination, groupStart))
                            {
                               dontAdvance = true;
@@ -286,13 +330,15 @@ public:
                      if(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);
@@ -326,13 +372,38 @@ public:
 
                }
             }
-            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);
@@ -349,19 +420,19 @@ public:
                pageFooter.anchor = Anchor { left = 0, bottom = (int)reportFooter.size.h, right = 0 };
             else
                pageFooter.anchor = Anchor { left = 0, bottom = 0, right = 0 };
-            
+
             pageFooter.Create();
          }
          if(nil && report.reportFooter)
          {
             reportFooter.Create();
          }
-         
+
          destination.EndPage(page);
 
          if(nil)
             break;
-         
+
          // still have to bump report footer if it does not fit...
       }
       pleaseWait.Destroy(0);
@@ -391,12 +462,13 @@ private:
    {
       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;
@@ -422,12 +494,8 @@ private:
 
 public class ReportDestination : Window
 {
-
-   int pageCount;
-
-   List<PreviewPage> pages { };
 public:
-   Report report;
+   public property Report report { watchable set { report = value; } get { return report; } }
 
    virtual void EndPage(Page page)
    {
@@ -437,11 +505,17 @@ public:
 
    virtual void AddPage(Page page);
    virtual Report GetReport() { return null; }
+private:
+   Report report;
+   int pageCount;
+
+   List<PreviewPage> pages { };
 }
 
 public class PrintedReport : ReportDestination
 {
    displayDriver = "Win32Printer";
+   fullRender = true;
 
    Page lastPage;
 
@@ -452,14 +526,19 @@ public class PrintedReport : ReportDestination
       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();
    }
@@ -487,16 +566,15 @@ public class ReportPreviewArea : ReportDestination
 
    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};
       page.Create();
       pageCount++;
    }
-   
+
    Report GetReport()
    {
       return report;
@@ -510,7 +588,7 @@ public class ReportPreviewArea : ReportDestination
 
 Array<FileFilter> csvFilters
 { [
-   { 
+   {
       $"Comma Separated Values Spreadsheet (*.csv)",
       "csv"
    },
@@ -523,24 +601,22 @@ public class CSVReport : ReportDestination
    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;
@@ -573,6 +649,7 @@ public class CSVReport : ReportDestination
    {
       char filePath[MAX_LOCATION];
       strcpy(filePath, report.title);
+      ChangeChars(filePath, "/\\:*?\"|<>", '_');
       strcat(filePath, ".csv");
       saveTo.master = master;
       saveTo.filePath = filePath;
@@ -581,14 +658,14 @@ public class CSVReport : ReportDestination
          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)
                      f.Puts("\n");
@@ -597,7 +674,7 @@ public class CSVReport : ReportDestination
                      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);
@@ -625,7 +702,7 @@ public class IdFilter : struct
 public:
    Id id;
    Field field;
-   
+
    bool RowMatch(Row row)
    {
       Id value;
@@ -655,6 +732,7 @@ public:
 
    bool activeOnly;
    Field activeField;
+   uint rowsCount;
 
    subclass(Detail) header;
    subclass(Detail) continuation;
@@ -665,7 +743,7 @@ public:
       filters.Free();
       delete row;
    }
-   
+
    virtual bool ShouldSkip()
    {
       return false;
@@ -687,7 +765,7 @@ public:
          result = row.Next();
       if(!result)
          return false;
-      
+
       if(reverseLink)
          reverseLink.row.GetData(reverseListFieldLink, reverseIdList);
 
@@ -775,12 +853,15 @@ public:
 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;
 
    Array<Grouping> groupings { };
 
-   property String title
+   property const String title
    {
       set
       {
@@ -805,15 +886,14 @@ public:
    {
       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
    {
@@ -825,7 +905,40 @@ public:
       }
    }
 
-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()
    {
       groupings.Free();
@@ -839,6 +952,7 @@ public class Detail : Window
 public:
    bool keepTogether;
    bool isLast;
+   int level;
 
    subclass(Detail) rowDetail;
 }