thinreports 0.12.1 → 0.13.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (177) hide show
  1. checksums.yaml +4 -4
  2. data/.github/dependabot.yml +3 -3
  3. data/.github/workflows/test.yml +28 -36
  4. data/.gitignore +1 -1
  5. data/CHANGELOG.md +19 -1
  6. data/Gemfile +11 -0
  7. data/README.md +12 -17
  8. data/Rakefile +17 -11
  9. data/lib/thinreports/basic_report/core/errors.rb +62 -0
  10. data/lib/thinreports/basic_report/core/format/base.rb +91 -0
  11. data/lib/thinreports/basic_report/core/shape/base/interface.rb +42 -0
  12. data/lib/thinreports/basic_report/core/shape/base/internal.rb +53 -0
  13. data/lib/thinreports/basic_report/core/shape/basic/block_format.rb +15 -0
  14. data/lib/thinreports/basic_report/core/shape/basic/block_interface.rb +34 -0
  15. data/lib/thinreports/basic_report/core/shape/basic/block_internal.rb +36 -0
  16. data/lib/thinreports/basic_report/core/shape/basic/format.rb +24 -0
  17. data/lib/thinreports/basic_report/core/shape/basic/interface.rb +87 -0
  18. data/lib/thinreports/basic_report/core/shape/basic/internal.rb +28 -0
  19. data/lib/thinreports/{core → basic_report/core}/shape/basic.rb +6 -4
  20. data/lib/thinreports/basic_report/core/shape/image_block/format.rb +14 -0
  21. data/lib/thinreports/basic_report/core/shape/image_block/interface.rb +25 -0
  22. data/lib/thinreports/basic_report/core/shape/image_block/internal.rb +19 -0
  23. data/lib/thinreports/{core → basic_report/core}/shape/image_block.rb +6 -4
  24. data/lib/thinreports/basic_report/core/shape/list/format.rb +92 -0
  25. data/lib/thinreports/basic_report/core/shape/list/manager.rb +231 -0
  26. data/lib/thinreports/basic_report/core/shape/list/page.rb +112 -0
  27. data/lib/thinreports/basic_report/core/shape/list/page_state.rb +50 -0
  28. data/lib/thinreports/basic_report/core/shape/list/section_format.rb +37 -0
  29. data/lib/thinreports/basic_report/core/shape/list/section_interface.rb +51 -0
  30. data/lib/thinreports/basic_report/core/shape/list/section_internal.rb +33 -0
  31. data/lib/thinreports/{core → basic_report/core}/shape/list.rb +6 -4
  32. data/lib/thinreports/basic_report/core/shape/manager/format.rb +33 -0
  33. data/lib/thinreports/basic_report/core/shape/manager/internal.rb +109 -0
  34. data/lib/thinreports/basic_report/core/shape/manager/target.rb +114 -0
  35. data/lib/thinreports/basic_report/core/shape/page_number/format.rb +32 -0
  36. data/lib/thinreports/basic_report/core/shape/page_number/interface.rb +31 -0
  37. data/lib/thinreports/basic_report/core/shape/page_number/internal.rb +57 -0
  38. data/lib/thinreports/{core → basic_report/core}/shape/page_number.rb +6 -4
  39. data/lib/thinreports/basic_report/core/shape/stack_view/format.rb +29 -0
  40. data/lib/thinreports/basic_report/core/shape/stack_view/interface.rb +19 -0
  41. data/lib/thinreports/basic_report/core/shape/stack_view/internal.rb +24 -0
  42. data/lib/thinreports/basic_report/core/shape/stack_view/row_format.rb +41 -0
  43. data/lib/thinreports/{core → basic_report/core}/shape/stack_view.rb +6 -4
  44. data/lib/thinreports/basic_report/core/shape/style/base.rb +149 -0
  45. data/lib/thinreports/basic_report/core/shape/style/basic.rb +24 -0
  46. data/lib/thinreports/basic_report/core/shape/style/graphic.rb +43 -0
  47. data/lib/thinreports/basic_report/core/shape/style/text.rb +122 -0
  48. data/lib/thinreports/basic_report/core/shape/text/format.rb +17 -0
  49. data/lib/thinreports/basic_report/core/shape/text/interface.rb +20 -0
  50. data/lib/thinreports/basic_report/core/shape/text/internal.rb +24 -0
  51. data/lib/thinreports/{core → basic_report/core}/shape/text.rb +6 -4
  52. data/lib/thinreports/basic_report/core/shape/text_block/format.rb +43 -0
  53. data/lib/thinreports/basic_report/core/shape/text_block/formatter/basic.rb +41 -0
  54. data/lib/thinreports/basic_report/core/shape/text_block/formatter/datetime.rb +25 -0
  55. data/lib/thinreports/basic_report/core/shape/text_block/formatter/number.rb +69 -0
  56. data/lib/thinreports/basic_report/core/shape/text_block/formatter/padding.rb +27 -0
  57. data/lib/thinreports/basic_report/core/shape/text_block/formatter.rb +38 -0
  58. data/lib/thinreports/basic_report/core/shape/text_block/interface.rb +37 -0
  59. data/lib/thinreports/basic_report/core/shape/text_block/internal.rb +75 -0
  60. data/lib/thinreports/{core → basic_report/core}/shape/text_block.rb +6 -4
  61. data/lib/thinreports/basic_report/core/shape.rb +44 -0
  62. data/lib/thinreports/basic_report/core/utils.rb +47 -0
  63. data/lib/thinreports/basic_report/generator/pdf/document/draw_shape.rb +108 -0
  64. data/lib/thinreports/basic_report/generator/pdf/document/draw_template_items.rb +71 -0
  65. data/lib/thinreports/basic_report/generator/pdf/document/font.rb +90 -0
  66. data/lib/thinreports/basic_report/generator/pdf/document/graphics/attributes.rb +149 -0
  67. data/lib/thinreports/basic_report/generator/pdf/document/graphics/basic.rb +137 -0
  68. data/lib/thinreports/basic_report/generator/pdf/document/graphics/image.rb +99 -0
  69. data/lib/thinreports/basic_report/generator/pdf/document/graphics/text.rb +180 -0
  70. data/lib/thinreports/basic_report/generator/pdf/document/graphics.rb +42 -0
  71. data/lib/thinreports/basic_report/generator/pdf/document/page.rb +96 -0
  72. data/lib/thinreports/basic_report/generator/pdf/document/parse_color.rb +51 -0
  73. data/lib/thinreports/basic_report/generator/pdf/document.rb +132 -0
  74. data/lib/thinreports/basic_report/generator/pdf/drawer/base.rb +50 -0
  75. data/lib/thinreports/basic_report/generator/pdf/drawer/list.rb +65 -0
  76. data/lib/thinreports/basic_report/generator/pdf/drawer/list_section.rb +51 -0
  77. data/lib/thinreports/basic_report/generator/pdf/drawer/page.rb +127 -0
  78. data/lib/thinreports/basic_report/generator/pdf/prawn_ext/calc_image_dimensions.rb +34 -0
  79. data/lib/thinreports/basic_report/generator/pdf/prawn_ext/width_of.rb +31 -0
  80. data/lib/thinreports/basic_report/generator/pdf.rb +66 -0
  81. data/lib/thinreports/basic_report/layout/base.rb +48 -0
  82. data/lib/thinreports/basic_report/layout/format.rb +67 -0
  83. data/lib/thinreports/basic_report/layout/legacy_schema.rb +383 -0
  84. data/lib/thinreports/basic_report/layout/version.rb +41 -0
  85. data/lib/thinreports/{layout.rb → basic_report/layout.rb} +6 -4
  86. data/lib/thinreports/basic_report/report/base.rb +173 -0
  87. data/lib/thinreports/basic_report/report/internal.rb +107 -0
  88. data/lib/thinreports/basic_report/report/page.rb +97 -0
  89. data/lib/thinreports/basic_report/report.rb +26 -0
  90. data/lib/thinreports/basic_report.rb +15 -0
  91. data/lib/thinreports/config.rb +1 -1
  92. data/lib/thinreports/section_report.rb +12 -0
  93. data/lib/thinreports/version.rb +1 -1
  94. data/lib/thinreports.rb +2 -13
  95. data/thinreports.gemspec +3 -7
  96. metadata +97 -154
  97. data/gemfiles/prawn-2.2.gemfile +0 -5
  98. data/gemfiles/prawn-2.3.gemfile +0 -5
  99. data/gemfiles/prawn-2.4.gemfile +0 -5
  100. data/lib/thinreports/core/errors.rb +0 -60
  101. data/lib/thinreports/core/format/base.rb +0 -89
  102. data/lib/thinreports/core/shape/base/interface.rb +0 -40
  103. data/lib/thinreports/core/shape/base/internal.rb +0 -51
  104. data/lib/thinreports/core/shape/basic/block_format.rb +0 -13
  105. data/lib/thinreports/core/shape/basic/block_interface.rb +0 -32
  106. data/lib/thinreports/core/shape/basic/block_internal.rb +0 -34
  107. data/lib/thinreports/core/shape/basic/format.rb +0 -22
  108. data/lib/thinreports/core/shape/basic/interface.rb +0 -85
  109. data/lib/thinreports/core/shape/basic/internal.rb +0 -26
  110. data/lib/thinreports/core/shape/image_block/format.rb +0 -12
  111. data/lib/thinreports/core/shape/image_block/interface.rb +0 -23
  112. data/lib/thinreports/core/shape/image_block/internal.rb +0 -17
  113. data/lib/thinreports/core/shape/list/format.rb +0 -90
  114. data/lib/thinreports/core/shape/list/manager.rb +0 -229
  115. data/lib/thinreports/core/shape/list/page.rb +0 -110
  116. data/lib/thinreports/core/shape/list/page_state.rb +0 -48
  117. data/lib/thinreports/core/shape/list/section_format.rb +0 -35
  118. data/lib/thinreports/core/shape/list/section_interface.rb +0 -49
  119. data/lib/thinreports/core/shape/list/section_internal.rb +0 -31
  120. data/lib/thinreports/core/shape/manager/format.rb +0 -31
  121. data/lib/thinreports/core/shape/manager/internal.rb +0 -107
  122. data/lib/thinreports/core/shape/manager/target.rb +0 -112
  123. data/lib/thinreports/core/shape/page_number/format.rb +0 -30
  124. data/lib/thinreports/core/shape/page_number/interface.rb +0 -29
  125. data/lib/thinreports/core/shape/page_number/internal.rb +0 -55
  126. data/lib/thinreports/core/shape/stack_view/format.rb +0 -27
  127. data/lib/thinreports/core/shape/stack_view/interface.rb +0 -17
  128. data/lib/thinreports/core/shape/stack_view/internal.rb +0 -22
  129. data/lib/thinreports/core/shape/stack_view/row_format.rb +0 -39
  130. data/lib/thinreports/core/shape/style/base.rb +0 -146
  131. data/lib/thinreports/core/shape/style/basic.rb +0 -22
  132. data/lib/thinreports/core/shape/style/graphic.rb +0 -41
  133. data/lib/thinreports/core/shape/style/text.rb +0 -120
  134. data/lib/thinreports/core/shape/text/format.rb +0 -15
  135. data/lib/thinreports/core/shape/text/interface.rb +0 -18
  136. data/lib/thinreports/core/shape/text/internal.rb +0 -22
  137. data/lib/thinreports/core/shape/text_block/format.rb +0 -41
  138. data/lib/thinreports/core/shape/text_block/formatter/basic.rb +0 -39
  139. data/lib/thinreports/core/shape/text_block/formatter/datetime.rb +0 -23
  140. data/lib/thinreports/core/shape/text_block/formatter/number.rb +0 -67
  141. data/lib/thinreports/core/shape/text_block/formatter/padding.rb +0 -25
  142. data/lib/thinreports/core/shape/text_block/formatter.rb +0 -34
  143. data/lib/thinreports/core/shape/text_block/interface.rb +0 -35
  144. data/lib/thinreports/core/shape/text_block/internal.rb +0 -73
  145. data/lib/thinreports/core/shape.rb +0 -42
  146. data/lib/thinreports/core/utils.rb +0 -45
  147. data/lib/thinreports/generate.rb +0 -11
  148. data/lib/thinreports/generator/pdf/document/draw_shape.rb +0 -106
  149. data/lib/thinreports/generator/pdf/document/draw_template_items.rb +0 -69
  150. data/lib/thinreports/generator/pdf/document/font.rb +0 -88
  151. data/lib/thinreports/generator/pdf/document/graphics/attributes.rb +0 -147
  152. data/lib/thinreports/generator/pdf/document/graphics/basic.rb +0 -135
  153. data/lib/thinreports/generator/pdf/document/graphics/image.rb +0 -98
  154. data/lib/thinreports/generator/pdf/document/graphics/text.rb +0 -178
  155. data/lib/thinreports/generator/pdf/document/graphics.rb +0 -40
  156. data/lib/thinreports/generator/pdf/document/page.rb +0 -94
  157. data/lib/thinreports/generator/pdf/document/parse_color.rb +0 -49
  158. data/lib/thinreports/generator/pdf/document.rb +0 -130
  159. data/lib/thinreports/generator/pdf/drawer/base.rb +0 -48
  160. data/lib/thinreports/generator/pdf/drawer/list.rb +0 -63
  161. data/lib/thinreports/generator/pdf/drawer/list_section.rb +0 -49
  162. data/lib/thinreports/generator/pdf/drawer/page.rb +0 -125
  163. data/lib/thinreports/generator/pdf/prawn_ext/calc_image_dimensions.rb +0 -32
  164. data/lib/thinreports/generator/pdf/prawn_ext/width_of.rb +0 -29
  165. data/lib/thinreports/generator/pdf.rb +0 -63
  166. data/lib/thinreports/layout/base.rb +0 -46
  167. data/lib/thinreports/layout/format.rb +0 -65
  168. data/lib/thinreports/layout/legacy_schema.rb +0 -381
  169. data/lib/thinreports/layout/version.rb +0 -39
  170. data/lib/thinreports/report/base.rb +0 -169
  171. data/lib/thinreports/report/internal.rb +0 -105
  172. data/lib/thinreports/report/page.rb +0 -95
  173. data/lib/thinreports/report.rb +0 -24
  174. /data/lib/thinreports/{core → basic_report/core}/shape/base.rb +0 -0
  175. /data/lib/thinreports/{core → basic_report/core}/shape/manager.rb +0 -0
  176. /data/lib/thinreports/{core → basic_report/core}/shape/style.rb +0 -0
  177. /data/lib/thinreports/{generator → basic_report/generator}/pdf/prawn_ext.rb +0 -0
@@ -0,0 +1,132 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'document/font'
4
+ require_relative 'document/parse_color'
5
+ require_relative 'document/graphics'
6
+ require_relative 'document/draw_shape'
7
+ require_relative 'document/draw_template_items'
8
+ require_relative 'document/page'
9
+
10
+ module Thinreports
11
+ module BasicReport
12
+ module Generator
13
+ class PDF
14
+ class Document
15
+ include Utils
16
+
17
+ include PDF::Font
18
+ include PDF::ParseColor
19
+ include PDF::Graphics
20
+ include PDF::DrawShape
21
+ include PDF::DrawTemplateItems
22
+ include PDF::Page
23
+
24
+ # @return [Prawn::Document]
25
+ attr_reader :pdf
26
+
27
+ # @param [String] title (nil)
28
+ # @param [Hash] security (nil)
29
+ def initialize(title: nil, security: nil)
30
+ @pdf = Prawn::Document.new(
31
+ skip_page_creation: true,
32
+ margin: [0, 0],
33
+ info: {
34
+ CreationDate: Time.now,
35
+ Creator: 'Thinreports Generator for Ruby ' + Thinreports::VERSION,
36
+ Title: title
37
+ }
38
+ )
39
+ # Setup to Prawn::Document.
40
+ setup_fonts
41
+ setup_custom_graphic_states
42
+
43
+ # Encrypts the document.
44
+ @pdf.encrypt_document(security) if security
45
+ end
46
+
47
+ # Delegate to Prawn::Document#render
48
+ # @see Prawn::Document#render
49
+ def render
50
+ result = pdf.render
51
+ finalize
52
+ result
53
+ end
54
+
55
+ # Delegate to Prawn::Document#render_file
56
+ # @see Prawn::Document#render_file
57
+ def render_file(*args)
58
+ finalize
59
+ pdf.render_file(*args)
60
+ end
61
+
62
+ # @param [Numeric, String] x
63
+ # @param [Numeric, String] y
64
+ def translate(x, y, &block)
65
+ x, y = rpos(x, y)
66
+ pdf.translate(x, y, &block)
67
+ end
68
+
69
+ # @param [String] stamp_id
70
+ # @param [Array<Numeric>] at (nil)
71
+ def stamp(stamp_id, at = nil)
72
+ if at.nil?
73
+ pdf.stamp(stamp_id)
74
+ else
75
+ pdf.stamp_at(stamp_id, rpos(*at))
76
+ end
77
+ end
78
+
79
+ # Delegate to Prawn::Document#create_stamp
80
+ # @param [String] id
81
+ # @see Prawn::Document#create_stamp
82
+ def create_stamp(id, &block)
83
+ pdf.create_stamp(id, &block)
84
+ end
85
+
86
+ # @see #pdf
87
+ def internal
88
+ @pdf
89
+ end
90
+
91
+ private
92
+
93
+ def finalize
94
+ clean_temp_images
95
+ end
96
+
97
+ # @param [Array<String, Numeric>] values
98
+ # @return [Numeric, Array<Numeric>, nil]
99
+ def s2f(*values)
100
+ return nil if values.empty?
101
+
102
+ if values.size == 1
103
+ value = values.first
104
+ return nil unless value
105
+ value.is_a?(::Numeric) ? value : value.to_f
106
+ else
107
+ values.map { |v| s2f(v) }
108
+ end
109
+ end
110
+
111
+ # @param [Numeric, String] x
112
+ # @param [Numeric, String] y
113
+ # @return [Array<Float>]
114
+ def map_to_upper_left_relative_position(x, y)
115
+ x, y = s2f(x, y)
116
+ [x, -y]
117
+ end
118
+ alias rpos map_to_upper_left_relative_position
119
+
120
+ # @param [Numeric, String] x
121
+ # @param [Numeric, String] y
122
+ # @return [Array<Float>]
123
+ def map_to_upper_left_position(x, y)
124
+ x, y = s2f(x, y)
125
+ [x, pdf.bounds.height - y]
126
+ end
127
+ alias pos map_to_upper_left_position
128
+ end
129
+ end
130
+ end
131
+ end
132
+ end
@@ -0,0 +1,50 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ class PDF
7
+ module Drawer
8
+ # @abstract
9
+ class Base
10
+ # @param [Thinreports::BasicReport::Generator::PDF::Document] pdf
11
+ # @param [Thinreports::BasicReport::Core::Shape::Manager::Format] format
12
+ def initialize(pdf, format)
13
+ @pdf = pdf
14
+ @format = format
15
+ @stamps = []
16
+ @draw_at = nil
17
+ end
18
+
19
+ # @abstract
20
+ def draw
21
+ raise NotImplementedError
22
+ end
23
+
24
+ private
25
+
26
+ # @param [Thinreports::BasicReport::Core::Shape::Base::Internal] shape
27
+ # @return [String]
28
+ def pdf_stamp_id(shape)
29
+ "#{@format.identifier}#{shape.identifier}"
30
+ end
31
+
32
+ # @overload pdf_stamp(shape_id)
33
+ # @param [String] shape_id
34
+ # @overload pdf_stamp(shape)
35
+ # @param [Thinreports::BasicReport::Core::Shape::Base::Internal] shape
36
+ def pdf_stamp(shape)
37
+ shape = pdf_stamp_id(shape) unless shape.is_a?(::String)
38
+ @pdf.stamp(shape, @draw_at)
39
+ end
40
+
41
+ # @param [Thinreports::BasicReport::Core::Shape::Base::Internal] shape
42
+ def create_pdf_stamp(shape, &block)
43
+ @pdf.create_stamp(pdf_stamp_id(shape), &block)
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ class PDF
7
+ module Drawer
8
+ class List < Base
9
+ # @param (see PDF::Drawer::Base#initialize)
10
+ def initialize(pdf, format)
11
+ super
12
+ @sections = {}
13
+ end
14
+
15
+ # @param [Thinreports::BasicReport::Core::Shape::List::PageState] list_page
16
+ def draw(list_page)
17
+ draw_section(list_page.header) if list_page.header
18
+ list_page.rows.each do |row|
19
+ draw_section(row)
20
+ end
21
+
22
+ # Returns Thinreports::BasicReport::Report::Page object
23
+ manager = list_page.parent.manager
24
+
25
+ list_id = list_page.id.to_s
26
+ manager.format.shapes.each do |id, shape|
27
+ next unless list_pageno?(list_id, shape)
28
+
29
+ shape = manager.final_shape(id)
30
+ @pdf.draw_shape_pageno(shape.internal,
31
+ list_page.no, list_page.manager.page_count)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ # @param [String] list_id
38
+ # @param [Thinreports::BasicReport::Core::Shape::Base::Format] shape
39
+ # @return [Boolean]
40
+ def list_pageno?(list_id, shape)
41
+ shape.type == Thinreports::BasicReport::Core::Shape::PageNumber::TYPE_NAME &&
42
+ shape.target == list_id
43
+ end
44
+
45
+ # @param [Thinreports::BasicReport::Core::Shape::List::SectionInterface] section
46
+ def draw_section(section)
47
+ internal = section.internal
48
+
49
+ base_top = @format.section_base_position_top(internal.section_name)
50
+ position = [internal.relative_left, base_top + internal.relative_top]
51
+
52
+ drawer(internal).draw(section, position)
53
+ end
54
+
55
+ # @param [Thinreports::BasicReport::Core::Shape::List::SectionInternal] section
56
+ # @return [Thinreports::BasicReport::Generator::PDF::Drawer::ListSection]
57
+ def drawer(section)
58
+ @sections[section.section_name] ||= ListSection.new(@pdf, section)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ class PDF
7
+ module Drawer
8
+ class ListSection < Page
9
+ # @param pdf (see PDF::Drawer::Page#initialize)
10
+ # @param section [Thinreports::BasicReport::Core::Shape::List::SectionInternal] section
11
+ def initialize(pdf, section)
12
+ super(pdf, section.format)
13
+ @section = section
14
+ @stamp_created = false
15
+ end
16
+
17
+ # @param [Thinreports::BasicReport::Core::Shape::List::SectionInternal] section
18
+ # @param [Array<Numeric>] at
19
+ def draw(section, at)
20
+ @draw_at = at
21
+ draw_section
22
+ super(section)
23
+ end
24
+
25
+ private
26
+
27
+ def draw_section
28
+ id = @format.identifier.to_s
29
+
30
+ unless @stamp_created
31
+ @pdf.create_stamp(id) { @pdf.draw_template_items(@format.attributes['items']) }
32
+ @stamp_created = true
33
+ end
34
+ pdf_stamp(id)
35
+ end
36
+
37
+ # @see Thinreports::BasicReport::Generator::PDF::Drawer::Page#draw_tblock_shape
38
+ def draw_tblock_shape(shape)
39
+ @pdf.translate(*@draw_at) { super }
40
+ end
41
+
42
+ # @see Thinreports::BasicReport::Generator::PDF::Drawer::Page#draw_iblock_shape
43
+ def draw_iblock_shape(shape)
44
+ @pdf.translate(*@draw_at) { super }
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,127 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ class PDF
7
+ module Drawer
8
+ class Page < Base
9
+ # @param (see PDF::Drawer::Base#initialize)
10
+ def initialize(pdf, format)
11
+ super
12
+ @lists = {}
13
+ end
14
+
15
+ # @param [Thinreports::BasicReport::Report::Page] page
16
+ def draw(page)
17
+ manager = page.manager
18
+
19
+ manager.format.shapes.each_key do |id|
20
+ shape = manager.final_shape(id)
21
+ next unless shape
22
+
23
+ shape = shape.internal
24
+
25
+ if shape.type_of?(Core::Shape::PageNumber::TYPE_NAME)
26
+ # Do not draw pageno if is not for Report
27
+ draw_pageno_shape(shape, page) if page.count? && shape.for_report?
28
+ else
29
+ draw_shape(shape)
30
+ end
31
+ end
32
+ end
33
+
34
+ private
35
+
36
+ def draw_shape(shape)
37
+ if shape.type_of?(Core::Shape::TextBlock::TYPE_NAME)
38
+ draw_tblock_shape(shape)
39
+ elsif shape.type_of?(Core::Shape::List::TYPE_NAME)
40
+ draw_list_shape(shape)
41
+ elsif shape.type_of?(Core::Shape::ImageBlock::TYPE_NAME)
42
+ draw_iblock_shape(shape)
43
+ else
44
+ id = shape.identifier
45
+ unless @stamps.include?(id)
46
+ create_basic_shape_stamp(shape)
47
+ @stamps << id
48
+ end
49
+ pdf_stamp(shape)
50
+ end
51
+ end
52
+
53
+ def draw_pageno_shape(shape, page)
54
+ @pdf.draw_shape_pageno(shape, page.no, page.report.page_count)
55
+ end
56
+
57
+ # @see #draw_shape
58
+ def draw_list_shape(shape)
59
+ drawer = @lists[shape.id] ||= List.new(@pdf, shape.format)
60
+ drawer.draw(shape)
61
+ end
62
+
63
+ # @see #draw_shape
64
+ def draw_tblock_shape(shape)
65
+ @pdf.draw_shape_tblock(shape)
66
+ end
67
+
68
+ # @see #draw_shape
69
+ def draw_iblock_shape(shape)
70
+ @pdf.draw_shape_iblock(shape)
71
+ end
72
+
73
+ # @param [Thinreports::BasicReport::Core::Shape::Base::Internal] shape
74
+ def create_basic_shape_stamp(shape)
75
+ if shape.type_of?('text')
76
+ create_text_stamp(shape)
77
+ elsif shape.type_of?('image')
78
+ create_image_stamp(shape)
79
+ elsif shape.type_of?('ellipse')
80
+ create_ellipse_stamp(shape)
81
+ elsif shape.type_of?('rect')
82
+ create_rect_stamp(shape)
83
+ elsif shape.type_of?('line')
84
+ create_line_stamp(shape)
85
+ end
86
+ end
87
+
88
+ # @see #create_basic_shape_stamp
89
+ def create_image_stamp(shape)
90
+ create_pdf_stamp(shape) do
91
+ @pdf.draw_shape_image(shape)
92
+ end
93
+ end
94
+
95
+ # @see #create_basic_shape_stamp
96
+ def create_rect_stamp(shape)
97
+ create_pdf_stamp(shape) do
98
+ @pdf.draw_shape_rect(shape)
99
+ end
100
+ end
101
+
102
+ # @see #create_basic_shape_stamp
103
+ def create_ellipse_stamp(shape)
104
+ create_pdf_stamp(shape) do
105
+ @pdf.draw_shape_ellipse(shape)
106
+ end
107
+ end
108
+
109
+ # @see #create_basic_shape_stamp
110
+ def create_line_stamp(shape)
111
+ create_pdf_stamp(shape) do
112
+ @pdf.draw_shape_line(shape)
113
+ end
114
+ end
115
+
116
+ # @see #create_basic_shape_stamp
117
+ def create_text_stamp(shape)
118
+ create_pdf_stamp(shape) do
119
+ @pdf.draw_shape_text(shape)
120
+ end
121
+ end
122
+ end
123
+ end
124
+ end
125
+ end
126
+ end
127
+ end
@@ -0,0 +1,34 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ module PrawnExt
7
+ module CalcImageDimensions
8
+ # Implement :auto_fit option for image size calculation.
9
+ #
10
+ # When the image is larger than the box, the original: fit option does not change
11
+ # the image size. The :auto_fit option changes the image size to fit in the box
12
+ # while maintaining the aspect ratio.
13
+ #
14
+ # Usage:
15
+ # image '/path/to/image.png', at: [100, 100], auto_fit: [100, 100]
16
+ #
17
+ def calc_image_dimensions(options)
18
+ if options[:auto_fit]
19
+ image_width = options[:width] || width
20
+ image_height = options[:height] || height
21
+
22
+ box_width, box_height = options.delete(:auto_fit)
23
+
24
+ options[:fit] = [box_width, box_height] if image_width > box_width || image_height > box_height
25
+ end
26
+ super(options)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
33
+
34
+ Prawn::Images::Image.prepend Thinreports::BasicReport::Generator::PrawnExt::CalcImageDimensions
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Generator
6
+ module PrawnExt
7
+ module WidthOf
8
+ # This patch fixes the character_spacing effect on text width calculation.
9
+ #
10
+ # The original #width_of:
11
+ #
12
+ # width_of('abcd') #=> 4 + 4 = 8
13
+ #
14
+ # The #width_of in this patch:
15
+ #
16
+ # width_of('abcd') #=> 4 + 3 = 7
17
+ #
18
+ def width_of(*)
19
+ width = super - character_spacing
20
+ width > 0 ? width : 0
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+
28
+ # Prawn v2.3 and later includes this patch by https://github.com/prawnpdf/prawn/pull/1117.
29
+ if Prawn::VERSION < '2.3.0'
30
+ Prawn::Document.prepend Thinreports::BasicReport::Generator::PrawnExt::WidthOf
31
+ end
@@ -0,0 +1,66 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'prawn'
4
+
5
+ module Thinreports
6
+ module BasicReport
7
+ module Generator
8
+ class PDF
9
+ # @return [Thinreports::BasicReport::Report::Base]
10
+ attr_reader :report
11
+
12
+ # @param [Thinreports::BasicReport::Report::Base] report
13
+ # @param [Hash] security (nil)
14
+ # @param [String] title (nil)
15
+ def initialize(report, security: nil, title: nil)
16
+ report.finalize
17
+
18
+ @report = report.internal
19
+ title ||= default_layout ? default_layout.format.report_title : nil
20
+
21
+ @document = Document.new(title: title, security: security)
22
+ @drawers = {}
23
+ end
24
+
25
+ # @param [String, nil] filename
26
+ # @return [String, nil]
27
+ def generate(filename = nil)
28
+ draw_report
29
+ filename ? @document.render_file(filename) : @document.render
30
+ end
31
+
32
+ def default_layout
33
+ report.default_layout
34
+ end
35
+
36
+ private
37
+
38
+ def draw_report
39
+ report.pages.each do |page|
40
+ draw_page(page)
41
+ end
42
+ end
43
+
44
+ def draw_page(page)
45
+ return @document.add_blank_page if page.blank?
46
+
47
+ format = page.layout.format
48
+ @document.start_new_page(format)
49
+
50
+ drawer(format).draw(page)
51
+ end
52
+
53
+ def drawer(format)
54
+ @drawers[format.identifier] ||= Drawer::Page.new(@document, format)
55
+ end
56
+ end
57
+ end
58
+ end
59
+ end
60
+
61
+ require_relative 'pdf/prawn_ext'
62
+ require_relative 'pdf/document'
63
+ require_relative 'pdf/drawer/base'
64
+ require_relative 'pdf/drawer/page'
65
+ require_relative 'pdf/drawer/list'
66
+ require_relative 'pdf/drawer/list_section'
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Thinreports
4
+ module BasicReport
5
+ module Layout
6
+ class Base
7
+ EXT_NAME = 'tlf'
8
+ include Utils
9
+
10
+ class << self
11
+ # @param [String] filename
12
+ # @return [Thinreports::BasicReport::Layout::Format]
13
+ # @raise [Thinreports::BasicReport::Errors::InvalidLayoutFormat]
14
+ # @raise [Thinreports::BasicReport::Errors::IncompatibleLayoutFormat]
15
+ def load_format(filename)
16
+ filename += ".#{EXT_NAME}" unless filename =~ /\.#{EXT_NAME}$/
17
+
18
+ raise Thinreports::BasicReport::Errors::LayoutFileNotFound unless File.exist?(filename)
19
+ # Build format.
20
+ Thinreports::BasicReport::Layout::Format.build(filename)
21
+ end
22
+ end
23
+
24
+ attr_reader :format
25
+
26
+ # @return [String]
27
+ attr_reader :filename
28
+
29
+ # @return [Symbol]
30
+ attr_reader :id
31
+
32
+ # @param [String] filename
33
+ # @param [Hash] options
34
+ # @option options [Symbol] :id (nil)
35
+ def initialize(filename, options = {})
36
+ @filename = filename
37
+ @format = self.class.load_format(filename)
38
+ @id = options[:id]
39
+ end
40
+
41
+ # @return [Boolean] Return the true if is default layout.
42
+ def default?
43
+ @id.nil?
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,67 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'json'
4
+
5
+ module Thinreports
6
+ module BasicReport
7
+ module Layout
8
+ class Format < Core::Shape::Manager::Format
9
+ config_reader last_version: %w[version]
10
+ config_reader report_title: %w[title]
11
+ config_reader page_paper_type: %w[report paper-type],
12
+ page_width: %w[report width],
13
+ page_height: %w[report height],
14
+ page_orientation: %w[report orientation]
15
+
16
+ class << self
17
+ def build(filename)
18
+ schema = JSON.parse(read_file(filename))
19
+ schema_version = Layout::Version.new(schema['version'])
20
+
21
+ unless schema_version.compatible?
22
+ raise Errors::IncompatibleLayoutFormat.new(
23
+ filename, schema['version'],
24
+ Layout::Version.compatible_rules.join(' and ')
25
+ )
26
+ end
27
+
28
+ if schema_version.legacy?
29
+ warn '[DEPRECATION] Support for the layout file with old format' \
30
+ ' that generated with Editor 0.8 or lower will be dropped in Thinreports 1.1.' \
31
+ ' Please convert to new layout format using Thinreports Editor 0.9 or 1.0.'
32
+ schema = Layout::LegacySchema.new(schema).upgrade
33
+ end
34
+
35
+ new schema
36
+ end
37
+
38
+ def read_file(filename)
39
+ File.read(filename, encoding: 'UTF-8')
40
+ end
41
+ end
42
+
43
+ def initialize(*)
44
+ super
45
+ initialize_items(attributes['items'])
46
+ end
47
+
48
+ def user_paper_type?
49
+ page_paper_type == 'user'
50
+ end
51
+
52
+ private
53
+
54
+ def initialize_items(item_schemas)
55
+ item_schemas.each do |item_schema|
56
+ id, type = item_schema.values_at 'id', 'type'
57
+
58
+ next if id.empty? && type != 'page-number'
59
+
60
+ item = Core::Shape::Format(type).new(item_schema)
61
+ shapes[item.id.to_sym] = item
62
+ end
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end