[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] [lmi] master 8fa972e 052/156: Add "Tabular Detail, continu
From: |
Greg Chicares |
Subject: |
[lmi-commits] [lmi] master 8fa972e 052/156: Add "Tabular Detail, continued" page to the PDF illustration |
Date: |
Tue, 30 Jan 2018 17:22:08 -0500 (EST) |
branch: master
commit 8fa972e4bfd75f7eaf8f3e61902d2c8ee00125e6
Author: Vadim Zeitlin <address@hidden>
Commit: Vadim Zeitlin <address@hidden>
Add "Tabular Detail, continued" page to the PDF illustration
The new page class shows how a logical page can request more than one
physical page for its contents and uses the existing wx_table_generator
to render a table on, possibly, multiple physical pages.
---
ledger_pdf_generator_wx.cpp | 205 +++++++++++++++++++++++++++++++++++++++++---
tabular_details2.mustache | 6 ++
wx_table_generator.cpp | 5 ++
wx_table_generator.hpp | 4 +
4 files changed, 206 insertions(+), 14 deletions(-)
diff --git a/ledger_pdf_generator_wx.cpp b/ledger_pdf_generator_wx.cpp
index 60a199f..c662e33 100644
--- a/ledger_pdf_generator_wx.cpp
+++ b/ledger_pdf_generator_wx.cpp
@@ -39,6 +39,7 @@
#include "pdf_writer_wx.hpp"
#include "value_cast.hpp"
#include "version.hpp"
+#include "wx_table_generator.hpp"
#include <wx/pdfdc.h>
@@ -48,6 +49,7 @@
#include <memory>
#include <sstream>
#include <stdexcept>
+#include <utility> // std::pair
#include <vector>
LMI_FORCE_LINKING_IN_SITU(ledger_pdf_generator_wx)
@@ -156,14 +158,13 @@ class html_interpolator
;
}
- protected:
- // Used by derived classes to define variables based on the existing
- // variables values.
+ // Return the value of a single scalar variable.
std::string evaluate(std::string const& name) const
{
return evaluator_(name);
}
+ // Return a single value of a vector variable.
std::string evaluate(std::string const& name, std::size_t index) const
{
return evaluator_(name, index);
@@ -728,15 +729,10 @@ class page_with_footer : public page
///
/// In addition to actually providing page_with_footer with the correct string
/// to show in the footer, this class implicitly handles the page count by
-/// incrementing it whenever a new object of this class is created.
+/// incrementing it whenever a new object of this class is pre-rendered.
class numbered_page : public page_with_footer
{
public:
- numbered_page()
- :this_page_number_(++last_page_number_)
- {
- }
-
void pre_render
(Ledger const& ledger
,pdf_writer_wx& writer
@@ -746,6 +742,8 @@ class numbered_page : public page_with_footer
{
page_with_footer::pre_render(ledger, writer, dc, interpolate_html);
+ this_page_number_ = ++last_page_number_;
+
extra_pages_ = get_extra_pages_needed
(ledger
,writer
@@ -791,10 +789,10 @@ class numbered_page : public page_with_footer
// Derived classes may override this method if they may need more than one
// physical page to show their contents.
virtual int get_extra_pages_needed
- (Ledger const& ledger
- ,pdf_writer_wx& writer
- ,wxDC& dc
- ,html_interpolator const& interpolate_html
+ (Ledger const& ledger
+ ,pdf_writer_wx& writer
+ ,wxDC& dc
+ ,html_interpolator const& interpolate_html
) const
{
stifle_warning_for_unused_value(ledger);
@@ -813,7 +811,7 @@ class numbered_page : public page_with_footer
}
static int last_page_number_;
- int this_page_number_;
+ int this_page_number_ = 0;
int extra_pages_ = 0;
};
@@ -1640,6 +1638,184 @@ class numeric_summary_page : public numbered_page
}
};
+class tabular_detail2_page : public numbered_page
+{
+ public:
+ void render
+ (Ledger const& ledger
+ ,pdf_writer_wx& writer
+ ,wxDC& dc
+ ,html_interpolator const& interpolate_html
+ ) override
+ {
+ numbered_page::render(ledger, writer, dc, interpolate_html);
+
+ wx_table_generator table{create_table_generator(writer, dc)};
+
+ std::vector<std::string> values(column_max);
+
+ // The table may need several pages, loop over them.
+ int const row_height = table.row_height();
+ int const year_max = ledger.GetMaxLength();
+ for(int year = 0; year < year_max; ++year)
+ {
+ int pos_y = render_or_measure_fixed_page_part
+ (table
+ ,writer
+ ,dc
+ ,interpolate_html
+ );
+
+ dc.SetPen(HIGHLIGHT_COL);
+ table.output_horz_separator(column_policy_year, column_max, pos_y);
+
+ for(; year < year_max; ++year)
+ {
+ values[column_policy_year] =
interpolate_html.evaluate("PolicyYear", year);
+ values[column_end_of_year_age] =
interpolate_html.evaluate("AttainedAge", year);
+ values[column_ill_crediting_rate] =
interpolate_html.evaluate("AnnGAIntRate_Current", year);
+ values[column_selected_face_amount] =
interpolate_html.evaluate("SpecAmt", year);
+
+ table.output_row(&pos_y, values.data());
+
+ // Insert a space after every 5th row for readability.
+ if((year + 1) % rows_per_group == 0)
+ {
+ pos_y += row_height;
+
+ // Start a new page if necessary, which will be the case
if we
+ // don't have enough space for another full group because
we
+ // don't want to have page breaks in the middle of a group.
+ if(pos_y >= get_footer_top() - rows_per_group*row_height)
+ {
+ next_page(dc);
+ numbered_page::render(ledger, writer, dc,
interpolate_html);
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ private:
+ enum
+ {column_policy_year
+ ,column_end_of_year_age
+ ,column_ill_crediting_rate
+ ,column_selected_face_amount
+ ,column_max
+ };
+
+ static int const rows_per_group = 5;
+
+ // Helper of render() and get_extra_pages_needed(): either outputs the
+ // fixed part of the page or just measures the space needed by it,
+ // depending on the output_mode parameter. Returns the vertical position of
+ // the table that should follow.
+ int render_or_measure_fixed_page_part
+ (wx_table_generator& table
+ ,pdf_writer_wx& writer
+ ,wxDC& dc
+ ,html_interpolator const& interpolate_html
+ ,enum_output_mode output_mode = e_output_normal
+ ) const
+ {
+ int pos_y = writer.get_vert_margin();
+
+ pos_y += writer.output_html
+ (writer.get_horz_margin()
+ ,pos_y
+ ,writer.get_page_width()
+ ,interpolate_html("{{>tabular_details2}}")
+ ,output_mode
+ );
+
+ // Decrease the font size for the table to match the main page
+ // body text size.
+ dc.SetFont(dc.GetFont().Smaller());
+
+ table.output_header(&pos_y, output_mode);
+
+ pos_y += 5;
+
+ return pos_y;
+ }
+
+ // Common part of render() and get_extra_pages_needed(): create the table
+ // generator to use.
+ wx_table_generator create_table_generator
+ (pdf_writer_wx& writer
+ ,wxDC& dc
+ ) const
+ {
+ wx_table_generator table
+ (dc
+ ,writer.get_horz_margin()
+ ,writer.get_page_width()
+ );
+
+ table.use_condensed_style();
+ table.align_right();
+
+ std::vector<std::pair<std::string, std::string>> const
+ columns =
+ {{ "Policy\nYear", "999" }
+ ,{ "End of\nYear Age", "999" }
+ ,{ "Illustrated\nCrediting Rate", "99.99%" }
+ ,{ "Selected\nFace Amount", "999,000,000" }
+ };
+
+ for(auto const& i : columns)
+ {
+ table.add_column(i.first, i.second);
+ }
+
+ return table;
+ }
+
+ // Override the base class method as the table may overflow onto the next
+ // page(s).
+ int get_extra_pages_needed
+ (Ledger const& ledger
+ ,pdf_writer_wx& writer
+ ,wxDC& dc
+ ,html_interpolator const& interpolate_html
+ ) const override
+ {
+ wx_table_generator table{create_table_generator(writer, dc)};
+
+ int const pos_y = render_or_measure_fixed_page_part
+ (table
+ ,writer
+ ,dc
+ ,interpolate_html
+ ,e_output_measure_only
+ );
+
+ int const rows_per_page = (get_footer_top() - pos_y) /
table.row_height();
+
+ if(rows_per_page < rows_per_group)
+ {
+ // We can't afford to continue in this case as we can never output
+ // the table as the template simply doesn't leave enough space for
+ // it on the page.
+ throw std::runtime_error("no space left for tabular details
table");
+ }
+
+ // Each group actually takes rows_per_group+1 rows because of the
+ // separator row between groups, hence the second +1, but there is no
+ // need for the separator after the last group, hence the first +1.
+ int const groups_per_page = (rows_per_page + 1) / (rows_per_group + 1);
+
+ // But we are actually interested in the number of years per page and
+ // not the number of groups.
+ int const years_per_page = groups_per_page * rows_per_group;
+
+ // Finally determine how many pages we need to show all the years.
+ return ledger.GetMaxLength() / years_per_page;
+ }
+};
+
// Regular illustration.
class pdf_illustration_regular : public pdf_illustration
{
@@ -1807,6 +1983,7 @@ class pdf_illustration_regular : public pdf_illustration
{
add<numeric_summary_page>();
}
+ add<tabular_detail2_page>();
}
};
diff --git a/tabular_details2.mustache b/tabular_details2.mustache
new file mode 100644
index 0000000..238e28d
--- /dev/null
+++ b/tabular_details2.mustache
@@ -0,0 +1,6 @@
+{{>header}}
+
+<p align="center">Tabular Detail, continued</p>
+
+<br></br>
+<br></br>
diff --git a/wx_table_generator.cpp b/wx_table_generator.cpp
index c8a80e7..a62d215 100644
--- a/wx_table_generator.cpp
+++ b/wx_table_generator.cpp
@@ -317,6 +317,11 @@ void wx_table_generator::output_horz_separator
do_output_horz_separator(x1, x2, y);
}
+int wx_table_generator::get_header_height() const
+{
+ return max_header_lines_*row_height_;
+}
+
void wx_table_generator::output_header(int* pos_y)
{
do_compute_column_widths_if_necessary();
diff --git a/wx_table_generator.hpp b/wx_table_generator.hpp
index e1da312..c9cbffb 100644
--- a/wx_table_generator.hpp
+++ b/wx_table_generator.hpp
@@ -80,6 +80,10 @@ class wx_table_generator
,std::string const& value
);
+ // Compute and return the height of the header without outputting it as
+ // output_header() does.
+ int get_header_height() const;
+
// Return the height of a single table row.
int row_height() const {return row_height_;}
- [lmi-commits] [lmi] master f575c94 003/156: Refactor more group_quote_pdf_gen_wx code to allow its reuse, (continued)
- [lmi-commits] [lmi] master f575c94 003/156: Refactor more group_quote_pdf_gen_wx code to allow its reuse, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 5e2fc70 007/156: Make HTML generation utilities more type-safe, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 7ed2bbf 027/156: Simplify footer generation code by moving font tag outside, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master d7244c1 043/156: Change the colour used for lines and borders, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 41ae40d 089/156: Fix wrong "<br>" tag in the header template, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master acb7aae 049/156: Add numbered_page::get_extra_pages_needed() hook, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master c0d68e1 122/156: Add rate of return pages of the individual placement illustration, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 875ca7d 039/156: Rename StateIsTX ledger variable to StateIsTexas, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 31048c8 047/156: Make wx_table_generator even more customizable, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 10dd0a9 051/156: Factor enum_output_mode into a separate header to allow its reuse, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 8fa972e 052/156: Add "Tabular Detail, continued" page to the PDF illustration,
Greg Chicares <=
- [lmi-commits] [lmi] master ca6e17c 031/156: Add function generating a standard header and use it, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master c378bc5 064/156: Remove unnecessary value_cast inclusion, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 41de2e2 140/156: Add helper expand_template() method, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 3e8e257 017/156: Add pdf_illustration_regular and narrative_summary_page, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 614fb47 135/156: Add supplemental reports pages to private placement illustrations, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 49cc809 072/156: Remove HTML construction helpers not needed any more, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master efc01fa 046/156: Allow disabling separator lines in wx_table_generator, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master e20544f 018/156: Add check for the ledger type, Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master a0a167e 144/156: Rename "compliance_tracking_number" template to "imprimatur", Greg Chicares, 2018/01/30
- [lmi-commits] [lmi] master 982c9f0 149/156: Remove consecutive blank lines from a Mustache template, Greg Chicares, 2018/01/30