Project

General

Profile

Feature #17570 » lib_redmine.rb_r13339.patch

Jun NAITOH, 2014-08-18 00:57

View differences:

Gemfile (working copy)
7 7
gem "builder", ">= 3.0.4"
8 8
gem "request_store", "1.0.5"
9 9
gem "mime-types"
10
gem "rbpdf", "~> 1.18.0"
10 11

  
11 12
# Optional gem for LDAP authentication
12 13
group :ldap do
lib/redmine/export/pdf.rb (working copy)
17 17
# along with this program; if not, write to the Free Software
18 18
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
19 19

  
20
require 'tcpdf'
21
require 'fpdf/chinese'
22
require 'fpdf/japanese'
23
require 'fpdf/korean'
20
require 'rbpdf'
24 21

  
25
if RUBY_VERSION < '1.9'
26
  require 'iconv'
27
end
28

  
29 22
module Redmine
30 23
  module Export
31 24
    module PDF
......
33 26
      include ActionView::Helpers::NumberHelper
34 27
      include IssuesHelper
35 28

  
36
      class ITCPDF < TCPDF
29
      class ITCPDF < RBPDF
37 30
        include Redmine::I18n
38 31
        attr_accessor :footer_date
39 32

  
......
42 35
          FileUtils.mkdir_p @@k_path_cache unless File::exist?(@@k_path_cache)
43 36
          set_language_if_valid lang
44 37
          pdf_encoding = l(:general_pdf_encoding).upcase
45
          super(orientation, 'mm', 'A4', (pdf_encoding == 'UTF-8'), pdf_encoding)
38
          super(orientation, 'mm', 'A4')
39
          set_print_header(false)
40
          set_rtl(l(:direction) == 'rtl')
41
          set_temp_rtl(l(:direction) == 'rtl' ? 'R' : 'L')
42

  
46 43
          case current_language.to_s.downcase
47 44
          when 'vi'
48 45
            @font_for_content = 'DejaVuSans'
49 46
            @font_for_footer  = 'DejaVuSans'
47
          when 'ja'
48
            @font_for_content = 'kozminproregular'
49
            @font_for_footer  = 'kozminproregular'
50
          when 'zh-tw' # Traditional Chinese (BIG5)
51
            @font_for_content = 'msungstdlight'
52
            @font_for_footer  = 'msungstdlight'
53
          when 'zh' # Simplified Chinese (GB18030)
54
            @font_for_content = 'stsongstdlight'
55
            @font_for_footer  = 'stsongstdlight'
56
          when 'ko' # Korean (UHC)
57
            @font_for_content = 'hysmyeongjostdmedium'
58
            @font_for_footer  = 'hysmyeongjostdmedium'
59
          when 'th' # Thai
60
            @font_for_content = 'freeserif'
61
            @font_for_footer  = 'freeserif'
50 62
          else
51 63
            case pdf_encoding
52 64
            when 'UTF-8'
53
              @font_for_content = 'FreeSans'
54
              @font_for_footer  = 'FreeSans'
55
            when 'CP949'
56
              extend(PDF_Korean)
57
              AddUHCFont()
58
              @font_for_content = 'UHC'
59
              @font_for_footer  = 'UHC'
60
            when 'CP932', 'SJIS', 'SHIFT_JIS'
61
              extend(PDF_Japanese)
62
              AddSJISFont()
63
              @font_for_content = 'SJIS'
64
              @font_for_footer  = 'SJIS'
65
            when 'GB18030'
66
              extend(PDF_Chinese)
67
              AddGBFont()
68
              @font_for_content = 'GB'
69
              @font_for_footer  = 'GB'
70
            when 'BIG5'
71
              extend(PDF_Chinese)
72
              AddBig5Font()
73
              @font_for_content = 'Big5'
74
              @font_for_footer  = 'Big5'
65
              @font_for_content = 'freesans'
66
              @font_for_footer  = 'freesans'
75 67
            else
76
              @font_for_content = 'Arial'
77
              @font_for_footer  = 'Helvetica'
68
              @font_for_content = 'helvetica'
69
              @font_for_footer  = 'helvetica'
78 70
            end
79 71
          end
80
          SetCreator(Redmine::Info.app_name)
81
          SetFont(@font_for_content)
82
          @outlines = []
83
          @outlineRoot = nil
72
          set_creator(Redmine::Info.app_name)
73
          set_font(@font_for_content)
74

  
75
          set_header_font([@font_for_content, '', 10])
76
          set_footer_font([@font_for_content, '', 8])
77
          set_default_monospaced_font(@font_for_content)
84 78
        end
85 79

  
86 80
        def SetFontStyle(style, size)
87
          SetFont(@font_for_content, style, size)
81
          style.delete!('B') if current_language.to_s.downcase == 'th' # FreeSerif Bold Thai font has problem.
82
          set_font(@font_for_content, style, size)
88 83
        end
89 84

  
90
        def SetTitle(txt)
91
          txt = begin
92
            utf16txt = to_utf16(txt)
93
            hextxt = "<FEFF"  # FEFF is BOM
94
            hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
95
            hextxt << ">"
96
          rescue
97
            txt
98
          end || ''
99
          super(txt)
100
        end
101

  
102
        def textstring(s)
103
          # Format a text string
104
          if s =~ /^</  # This means the string is hex-dumped.
105
            return s
106
          else
107
            return '('+escape(s)+')'
108
          end
109
        end
110

  
111 85
        def fix_text_encoding(txt)
112 86
          RDMPdfEncoding::rdm_from_utf8(txt, l(:general_pdf_encoding))
113 87
        end
......
119 93
          html
120 94
        end
121 95

  
122
        # Encodes an UTF-8 string to UTF-16BE
123
        def to_utf16(str)
124
          if str.respond_to?(:encode)
125
            str.encode('UTF-16BE')
126
          else
127
            Iconv.conv('UTF-16BE', 'UTF-8', str)
128
          end
129
        end
130

  
131 96
        def RDMCell(w ,h=0, txt='', border=0, ln=0, align='', fill=0, link='')
132
          Cell(w, h, fix_text_encoding(txt), border, ln, align, fill, link)
97
          cell(w, h, txt, border, ln, align, fill, link)
133 98
        end
134 99

  
135 100
        def RDMMultiCell(w, h=0, txt='', border=0, align='', fill=0, ln=1)
136
          MultiCell(w, h, fix_text_encoding(txt), border, align, fill, ln)
101
          multi_cell(w, h, txt, border, align, fill, ln)
137 102
        end
138 103

  
139 104
        def RDMwriteHTMLCell(w, h, x, y, txt='', attachments=[], border=0, ln=1, fill=0)
140 105
          @attachments = attachments
106

  
107
          css_tag = ' <style>
108
          table, td {
109
            border: 2px #ff0000 solid;
110
          }
111
          th {  background-color:#EEEEEE; padding: 4px; white-space:nowrap; text-align: center;  font-style: bold;}
112
          pre {
113
            background-color: #fafafa;
114
          }
115
          </style>'
116

  
141 117
          writeHTMLCell(w, h, x, y,
142
            fix_text_encoding(formatted_text(txt)),
118
            css_tag + formatted_text(txt),
143 119
            border, ln, fill)
144 120
        end
145 121

  
146
        def getImageFilename(attrname)
122
        def get_image_filename(attrname)
147 123
          # attrname: general_pdf_encoding string file/uri name
148
          atta = RDMPdfEncoding.attach(@attachments, attrname, l(:general_pdf_encoding))
124
          atta = RDMPdfEncoding.attach(@attachments, attrname, "UTF-8")
149 125
          if atta
150 126
            return atta.diskfile
151 127
          else
......
153 129
          end
154 130
        end
155 131

  
156
        def Footer
157
          SetFont(@font_for_footer, 'I', 8)
158
          SetY(-15)
159
          SetX(15)
160
          RDMCell(0, 5, @footer_date, 0, 0, 'L')
161
          SetY(-15)
162
          SetX(-30)
163
          RDMCell(0, 5, PageNo().to_s + '/{nb}', 0, 0, 'C')
164
        end
165

  
166
        def Bookmark(txt, level=0, y=0)
167
          if (y == -1)
168
            y = GetY()
132
        def get_sever_url(url)
133
          if !empty_string(url) and (url[0, 1] == '/')
134
            Setting.host_name.split('/')[0] + url
135
          else
136
            url
169 137
          end
170
          @outlines << {:t => txt, :l => level, :p => PageNo(), :y => (@h - y)*@k}
171 138
        end
172 139

  
173
        def bookmark_title(txt)
174
          txt = begin
175
            utf16txt = to_utf16(txt)
176
            hextxt = "<FEFF"  # FEFF is BOM
177
            hextxt << utf16txt.unpack("C*").map {|x| sprintf("%02X",x) }.join
178
            hextxt << ">"
179
          rescue
180
            txt
181
          end || ''
182
        end
183

  
184
        def putbookmarks
185
          nb=@outlines.size
186
          return if (nb==0)
187
          lru=[]
188
          level=0
189
          @outlines.each_with_index do |o, i|
190
            if(o[:l]>0)
191
              parent=lru[o[:l]-1]
192
              #Set parent and last pointers
193
              @outlines[i][:parent]=parent
194
              @outlines[parent][:last]=i
195
              if (o[:l]>level)
196
                #Level increasing: set first pointer
197
                @outlines[parent][:first]=i
198
              end
199
            else
200
              @outlines[i][:parent]=nb
201
            end
202
            if (o[:l]<=level && i>0)
203
              #Set prev and next pointers
204
              prev=lru[o[:l]]
205
              @outlines[prev][:next]=i
206
              @outlines[i][:prev]=prev
207
            end
208
            lru[o[:l]]=i
209
            level=o[:l]
140
        def Footer
141
          set_font(@font_for_footer, 'I', 8)
142
          set_x(15)
143
          if get_rtl
144
            RDMCell(0, 5, @footer_date, 0, 0, 'R')
145
          else
146
            RDMCell(0, 5, @footer_date, 0, 0, 'L')
210 147
          end
211
          #Outline items
212
          n=self.n+1
213
          @outlines.each_with_index do |o, i|
214
            newobj()
215
            out('<</Title '+bookmark_title(o[:t]))
216
            out("/Parent #{n+o[:parent]} 0 R")
217
            if (o[:prev])
218
              out("/Prev #{n+o[:prev]} 0 R")
219
            end
220
            if (o[:next])
221
              out("/Next #{n+o[:next]} 0 R")
222
            end
223
            if (o[:first])
224
              out("/First #{n+o[:first]} 0 R")
225
            end
226
            if (o[:last])
227
              out("/Last #{n+o[:last]} 0 R")
228
            end
229
            out("/Dest [%d 0 R /XYZ 0 %.2f null]" % [1+2*o[:p], o[:y]])
230
            out('/Count 0>>')
231
            out('endobj')
232
          end
233
          #Outline root
234
          newobj()
235
          @outlineRoot=self.n
236
          out("<</Type /Outlines /First #{n} 0 R")
237
          out("/Last #{n+lru[0]} 0 R>>")
238
          out('endobj')
148
          set_x(-30)
149
          RDMCell(0, 5, get_alias_num_page() + '/' + get_alias_nb_pages(), 0, 0, 'C')
239 150
        end
240

  
241
        def putresources()
242
          super
243
          putbookmarks()
244
        end
245

  
246
        def putcatalog()
247
          super
248
          if(@outlines.size > 0)
249
            out("/Outlines #{@outlineRoot} 0 R")
250
            out('/PageMode /UseOutlines')
251
          end
252
        end
253 151
      end
254 152

  
255 153
      # fetch row values
......
280 178
        # calculate statistics
281 179
        #  by captions
282 180
        pdf.SetFontStyle('B',8)
283
        col_padding = pdf.GetStringWidth('OO')
284
        col_width_min = query.inline_columns.map {|v| pdf.GetStringWidth(v.caption) + col_padding}
181
        margins = pdf.get_margins
182
        col_padding = margins['cell']
183
        col_width_min = query.inline_columns.map {|v| pdf.get_string_width(v.caption) + col_padding}
285 184
        col_width_max = Array.new(col_width_min)
286 185
        col_width_avg = Array.new(col_width_min)
186
        col_min = pdf.get_string_width('OO') + col_padding * 2
187
        if table_width > col_min * col_width_avg.length 
188
          table_width -= col_min * col_width_avg.length 
189
        else
190
          col_min = pdf.get_string_width('O') + col_padding * 2
191
          if table_width > col_min * col_width_avg.length 
192
            table_width -= col_min * col_width_avg.length 
193
          else
194
            ratio = table_width / col_width_avg.inject(0, :+)
195
            return col_width = col_width_avg.map {|w| w * ratio}
196
          end
197
        end
287 198
        word_width_max = query.inline_columns.map {|c|
288 199
          n = 10
289 200
          c.caption.split.each {|w|
290
            x = pdf.GetStringWidth(w) + col_padding
201
            x = pdf.get_string_width(w) + col_padding
291 202
            n = x if n < x
292 203
          }
293 204
          n
......
295 206

  
296 207
        #  by properties of issues
297 208
        pdf.SetFontStyle('',8)
298
        col_padding = pdf.GetStringWidth('OO')
299 209
        k = 1
300 210
        issue_list(issues) {|issue, level|
301 211
          k += 1
302 212
          values = fetch_row_values(issue, query, level)
303 213
          values.each_with_index {|v,i|
304
            n = pdf.GetStringWidth(v) + col_padding
214
            n = pdf.get_string_width(v) + col_padding * 2
305 215
            col_width_max[i] = n if col_width_max[i] < n
306 216
            col_width_min[i] = n if col_width_min[i] > n
307 217
            col_width_avg[i] += n
308 218
            v.split.each {|w|
309
              x = pdf.GetStringWidth(w) + col_padding
219
              x = pdf.get_string_width(w) + col_padding
310 220
              word_width_max[i] = x if word_width_max[i] < x
311 221
            }
312 222
          }
......
342 252
        while done == 0
343 253
          # calculate free & locked columns width
344 254
          done = 1
345
          fix_col_width = 0
346
          free_col_width = 0
347
          col_width.each_with_index do |w,i|
348
            if col_fix[i] == 1
349
              fix_col_width += w
350
            else
351
              free_col_width += w
352
            end
353
          end
255
          ratio = table_width / col_width.inject(0, :+)
354 256

  
355
          # calculate column normalizing ratio
356
          if free_col_width == 0
357
            ratio = table_width / col_width.inject(0, :+)
358
          else
359
            ratio = (table_width - fix_col_width) / free_col_width
360
          end
361

  
362 257
          # correct columns width
363 258
          col_width.each_with_index do |w,i|
364 259
            if col_fix[i] == 0
......
377 272
            end
378 273
          end
379 274
        end
275

  
276
        ratio = table_width / col_width.inject(0, :+)
277
        col_width.map! {|v| v * ratio + col_min}
380 278
        col_width
381 279
      end
382 280

  
383 281
      def render_table_header(pdf, query, col_width, row_height, table_width)
384 282
        # headers
385 283
        pdf.SetFontStyle('B',8)
386
        pdf.SetFillColor(230, 230, 230)
284
        pdf.set_fill_color(230, 230, 230)
387 285

  
388
        # render it background to find the max height used
389
        base_x = pdf.GetX
390
        base_y = pdf.GetY
391
        max_height = issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true)
392
        pdf.Rect(base_x, base_y, table_width, max_height, 'FD')
393
        pdf.SetXY(base_x, base_y)
286
        base_x     = pdf.get_x
287
        base_y     = pdf.get_y
288
        max_height = get_issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, true)
394 289

  
395 290
        # write the cells on page
396
        issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, row_height, true)
397
        issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, 0, col_width)
398
        pdf.SetY(base_y + max_height)
291
        issues_to_pdf_write_cells(pdf, query.inline_columns, col_width, max_height, true)
292
        pdf.set_xy(base_x, base_y + max_height)
399 293

  
400 294
        # rows
401 295
        pdf.SetFontStyle('',8)
402
        pdf.SetFillColor(255, 255, 255)
296
        pdf.set_fill_color(255, 255, 255)
403 297
      end
404 298

  
405 299
      # Returns a PDF string of a list of issues
......
407 301
        pdf = ITCPDF.new(current_language, "L")
408 302
        title = query.new_record? ? l(:label_issue_plural) : query.name
409 303
        title = "#{project} - #{title}" if project
410
        pdf.SetTitle(title)
304
        pdf.set_title(title)
411 305
        pdf.alias_nb_pages
412 306
        pdf.footer_date = format_date(Date.today)
413
        pdf.SetAutoPageBreak(false)
414
        pdf.AddPage("L")
307
        pdf.set_auto_page_break(false)
308
        pdf.add_page("L")
415 309

  
416 310
        # Landscape A4 = 210 x 297 mm
417
        page_height   = 210
418
        page_width    = 297
419
        left_margin   = 10
420
        right_margin  = 10
421
        bottom_margin = 20
311
        page_height   = pdf.get_page_height # 210
312
        page_width    = pdf.get_page_width  # 297
313
        left_margin   = pdf.get_original_margins['left'] # 10
314
        right_margin  = pdf.get_original_margins['right'] # 10
315
        bottom_margin = pdf.get_footer_margin
422 316
        row_height    = 4
423 317

  
424 318
        # column widths
......
438 332
        # title
439 333
        pdf.SetFontStyle('B',11)
440 334
        pdf.RDMCell(190,10, title)
441
        pdf.Ln
335
        pdf.ln
336

  
442 337
        render_table_header(pdf, query, col_width, row_height, table_width)
443 338
        previous_group = false
444 339
        issue_list(issues) do |issue, level|
......
447 342
            pdf.SetFontStyle('B',10)
448 343
            group_label = group.blank? ? 'None' : group.to_s.dup
449 344
            group_label << " (#{query.issue_count_by_group[group]})"
450
            pdf.Bookmark group_label, 0, -1
345
            pdf.bookmark group_label, 0, -1
451 346
            pdf.RDMCell(table_width, row_height * 2, group_label, 1, 1, 'L')
452 347
            pdf.SetFontStyle('',8)
453 348
            previous_group = group
......
456 351
          # fetch row values
457 352
          col_values = fetch_row_values(issue, query, level)
458 353

  
459
          # render it off-page to find the max height used
460
          base_x = pdf.GetX
461
          base_y = pdf.GetY
462
          pdf.SetY(2 * page_height)
463
          max_height = issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
464
          pdf.SetXY(base_x, base_y)
465

  
466 354
          # make new page if it doesn't fit on the current one
355
          base_y     = pdf.get_y
356
          max_height = get_issues_to_pdf_write_cells(pdf, col_values, col_width)
467 357
          space_left = page_height - base_y - bottom_margin
468 358
          if max_height > space_left
469
            pdf.AddPage("L")
359
            pdf.add_page("L")
470 360
            render_table_header(pdf, query, col_width, row_height, table_width)
471
            base_x = pdf.GetX
472
            base_y = pdf.GetY
361
            base_y = pdf.get_y
473 362
          end
474 363

  
475 364
          # write the cells on page
476
          issues_to_pdf_write_cells(pdf, col_values, col_width, row_height)
477
          issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, 0, col_width)
478
          pdf.SetY(base_y + max_height)
365
          issues_to_pdf_write_cells(pdf, col_values, col_width, max_height)
366
          pdf.set_y(base_y + max_height)
479 367

  
480 368
          if query.has_column?(:description) && issue.description?
481
            pdf.SetX(10)
482
            pdf.SetAutoPageBreak(true, 20)
483
            pdf.RDMwriteHTMLCell(0, 5, 10, 0, issue.description.to_s, issue.attachments, "LRBT")
484
            pdf.SetAutoPageBreak(false)
369
            pdf.set_x(10)
370
            pdf.set_auto_page_break(true, bottom_margin)
371
            pdf.RDMwriteHTMLCell(0, 5, 10, '', issue.description.to_s, issue.attachments, "LRBT")
372
            pdf.set_auto_page_break(false)
485 373
          end
486 374
        end
487 375

  
......
489 377
          pdf.SetFontStyle('B',10)
490 378
          pdf.RDMCell(0, row_height, '...')
491 379
        end
492
        pdf.Output
380
        pdf.output
493 381
      end
494 382

  
383
      # returns the maximum height of MultiCells
384
      def get_issues_to_pdf_write_cells(pdf, col_values, col_widths, head=false)
385
        heights = []
386
        col_values.each_with_index do |column, i|
387
          heights << pdf.get_string_height(col_widths[i], head ? column.caption : column)
388
        end
389
        return heights.max
390
      end
391

  
495 392
      # Renders MultiCells and returns the maximum height used
496 393
      def issues_to_pdf_write_cells(pdf, col_values, col_widths, row_height, head=false)
497
        base_y = pdf.GetY
498
        max_height = row_height
499 394
        col_values.each_with_index do |column, i|
500
          col_x = pdf.GetX
501
          if head == true
502
            pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
503
          else
504
            pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
505
          end
506
          max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
507
          pdf.SetXY(col_x + col_widths[i], base_y)
395
          pdf.RDMMultiCell(col_widths[i], row_height, head ? column.caption : column.strip, 1, '', 1, 0)
508 396
        end
509
        return max_height
510 397
      end
511 398

  
512 399
      # Draw lines to close the row (MultiCell border drawing in not uniform)
513 400
      #
514 401
      #  parameter "col_id_width" is not used. it is kept for compatibility.
515 402
      def issues_to_pdf_draw_borders(pdf, top_x, top_y, lower_y,
516
                                     col_id_width, col_widths)
403
                                     col_id_width, col_widths, rtl=false)
517 404
        col_x = top_x
518
        pdf.Line(col_x, top_y, col_x, lower_y)    # id right border
405
        pdf.line(col_x, top_y, col_x, lower_y)    # id right border
519 406
        col_widths.each do |width|
520
          col_x += width
521
          pdf.Line(col_x, top_y, col_x, lower_y)  # columns right border
407
          if rtl
408
            col_x -= width
409
          else
410
            col_x += width
411
          end
412
          pdf.line(col_x, top_y, col_x, lower_y)  # columns right border
522 413
        end
523
        pdf.Line(top_x, top_y, top_x, lower_y)    # left border
524
        pdf.Line(top_x, lower_y, col_x, lower_y)  # bottom border
414
        pdf.line(top_x, top_y, top_x, lower_y)    # left border
415
        pdf.line(top_x, lower_y, col_x, lower_y)  # bottom border
525 416
      end
526 417

  
527 418
      # Returns a PDF string of a single issue
528 419
      def issue_to_pdf(issue, assoc={})
529 420
        pdf = ITCPDF.new(current_language)
530
        pdf.SetTitle("#{issue.project} - #{issue.tracker} ##{issue.id}")
421
        pdf.set_title("#{issue.project} - #{issue.tracker} ##{issue.id}")
531 422
        pdf.alias_nb_pages
532 423
        pdf.footer_date = format_date(Date.today)
533
        pdf.AddPage
424
        pdf.add_page
534 425
        pdf.SetFontStyle('B',11)
535 426
        buf = "#{issue.project} - #{issue.tracker} ##{issue.id}"
536 427
        pdf.RDMMultiCell(190, 5, buf)
537 428
        pdf.SetFontStyle('',8)
538
        base_x = pdf.GetX
429
        base_x = pdf.get_x
539 430
        i = 1
540 431
        issue.ancestors.visible.each do |ancestor|
541
          pdf.SetX(base_x + i)
432
          pdf.set_x(base_x + i)
542 433
          buf = "#{ancestor.tracker} # #{ancestor.id} (#{ancestor.status.to_s}): #{ancestor.subject}"
543 434
          pdf.RDMMultiCell(190 - i, 5, buf)
544 435
          i += 1 if i < 35
......
547 438
        pdf.RDMMultiCell(190 - i, 5, issue.subject.to_s)
548 439
        pdf.SetFontStyle('',8)
549 440
        pdf.RDMMultiCell(190, 5, "#{format_time(issue.created_on)} - #{issue.author}")
550
        pdf.Ln
441
        pdf.ln
551 442

  
552 443
        left = []
553 444
        left << [l(:field_status), issue.status]
......
576 467
          (i < half ? left : right) << [custom_value.custom_field.name, show_value(custom_value, false)]
577 468
        end
578 469

  
470
        if pdf.get_rtl
471
          border_first_top = 'RT'
472
          border_last_top  = 'LT'
473
          border_first = 'R'
474
          border_last  = 'L'
475
        else
476
          border_first_top = 'LT'
477
          border_last_top  = 'RT'
478
          border_first = 'L'
479
          border_last  = 'R'
480
        end
481

  
579 482
        rows = left.size > right.size ? left.size : right.size
580 483
        rows.times do |i|
484
          heights = []
485
          pdf.SetFontStyle('B',9)
581 486
          item = left[i]
487
          heights << pdf.get_string_height(35, item ? "#{item.first}:" : "")
488
          item = right[i]
489
          heights << pdf.get_string_height(35, item ? "#{item.first}:" : "")
490
          pdf.SetFontStyle('',9)
491
          item = left[i]
492
          heights << pdf.get_string_height(60, item ? item.last.to_s  : "")
493
          item = right[i]
494
          heights << pdf.get_string_height(60, item ? item.last.to_s  : "")
495
          height = heights.max
496

  
497
          item = left[i]
582 498
          pdf.SetFontStyle('B',9)
583
          pdf.RDMCell(35,5, item ? "#{item.first}:" : "", i == 0 ? "LT" : "L")
499
          pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "", (i == 0 ? border_first_top : border_first), '', 0, 0)
584 500
          pdf.SetFontStyle('',9)
585
          pdf.RDMCell(60,5, item ? item.last.to_s : "", i == 0 ? "RT" : "R")
501
          pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 0)
586 502

  
587 503
          item = right[i]
588 504
          pdf.SetFontStyle('B',9)
589
          pdf.RDMCell(35,5, item ? "#{item.first}:" : "", i == 0 ? "LT" : "L")
505
          pdf.RDMMultiCell(35, height, item ? "#{item.first}:" : "",  (i == 0 ? border_first_top : border_first), '', 0, 0)
590 506
          pdf.SetFontStyle('',9)
591
          pdf.RDMCell(60,5, item ? item.last.to_s : "", i == 0 ? "RT" : "R")
592
          pdf.Ln
507
          pdf.RDMMultiCell(60, height, item ? item.last.to_s : "", (i == 0 ? border_last_top : border_last), '', 0, 2)
508

  
509
          pdf.set_x(base_x)
593 510
        end
594 511

  
595 512
        pdf.SetFontStyle('B',9)
......
597 514
        pdf.SetFontStyle('',9)
598 515

  
599 516
        # Set resize image scale
600
        pdf.SetImageScale(1.6)
601
        pdf.RDMwriteHTMLCell(35+155, 5, 0, 0,
517
        pdf.set_image_scale(1.6)
518
        pdf.RDMwriteHTMLCell(35+155, 5, '', '',
602 519
              issue.description.to_s, issue.attachments, "LRB")
603 520

  
604 521
        unless issue.leaf?
......
606 523
          truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 90 : 65 )
607 524
          pdf.SetFontStyle('B',9)
608 525
          pdf.RDMCell(35+155,5, l(:label_subtask_plural) + ":", "LTR")
609
          pdf.Ln
526
          pdf.ln
610 527
          issue_list(issue.descendants.visible.sort_by(&:lft)) do |child, level|
611 528
            buf = "#{child.tracker} # #{child.id}: #{child.subject}".
612 529
                    truncate(truncate_length)
613 530
            level = 10 if level >= 10
614 531
            pdf.SetFontStyle('',8)
615
            pdf.RDMCell(35+135,5, (level >=1 ? "  " * level : "") + buf, "L")
532
            pdf.RDMCell(35+135,5, (level >=1 ? "  " * level : "") + buf, border_first)
616 533
            pdf.SetFontStyle('B',8)
617
            pdf.RDMCell(20,5, child.status.to_s, "R")
618
            pdf.Ln
534
            pdf.RDMCell(20,5, child.status.to_s, border_last)
535
            pdf.ln
619 536
          end
620 537
        end
621 538

  
......
625 542
          truncate_length = ( l(:general_pdf_encoding).upcase == "UTF-8" ? 80 : 60 )
626 543
          pdf.SetFontStyle('B',9)
627 544
          pdf.RDMCell(35+155,5, l(:label_related_issues) + ":", "LTR")
628
          pdf.Ln
545
          pdf.ln
629 546
          relations.each do |relation|
630 547
            buf = ""
631 548
            buf += "#{l(relation.label_for(issue))} "
......
639 556
                   " # #{relation.other_issue(issue).id}: #{relation.other_issue(issue).subject}"
640 557
            buf = buf.truncate(truncate_length)
641 558
            pdf.SetFontStyle('', 8)
642
            pdf.RDMCell(35+155-60, 5, buf, "L")
559
            pdf.RDMCell(35+155-60, 5, buf, border_first)
643 560
            pdf.SetFontStyle('B',8)
644 561
            pdf.RDMCell(20,5, relation.other_issue(issue).status.to_s, "")
645 562
            pdf.RDMCell(20,5, format_date(relation.other_issue(issue).start_date), "")
646
            pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), "R")
647
            pdf.Ln
563
            pdf.RDMCell(20,5, format_date(relation.other_issue(issue).due_date), border_last)
564
            pdf.ln
648 565
          end
649 566
        end
650 567
        pdf.RDMCell(190,5, "", "T")
651
        pdf.Ln
568
        pdf.ln
652 569

  
653 570
        if issue.changesets.any? &&
654 571
             User.current.allowed_to?(:view_changesets, issue.project)
655 572
          pdf.SetFontStyle('B',9)
656 573
          pdf.RDMCell(190,5, l(:label_associated_revisions), "B")
657
          pdf.Ln
574
          pdf.ln
658 575
          for changeset in issue.changesets
659 576
            pdf.SetFontStyle('B',8)
660 577
            csstr  = "#{l(:label_revision)} #{changeset.format_identifier} - "
661 578
            csstr += format_time(changeset.committed_on) + " - " + changeset.author.to_s
662 579
            pdf.RDMCell(190, 5, csstr)
663
            pdf.Ln
580
            pdf.ln
664 581
            unless changeset.comments.blank?
665 582
              pdf.SetFontStyle('',8)
666
              pdf.RDMwriteHTMLCell(190,5,0,0,
583
              pdf.RDMwriteHTMLCell(190,5,'','',
667 584
                    changeset.comments.to_s, issue.attachments, "")
668 585
            end
669
            pdf.Ln
586
            pdf.ln
670 587
          end
671 588
        end
672 589

  
673 590
        if assoc[:journals].present?
674 591
          pdf.SetFontStyle('B',9)
675 592
          pdf.RDMCell(190,5, l(:label_history), "B")
676
          pdf.Ln
593
          pdf.ln
677 594
          assoc[:journals].each do |journal|
678 595
            pdf.SetFontStyle('B',8)
679 596
            title = "##{journal.indice} - #{format_time(journal.created_on)} - #{journal.user}"
680 597
            title << " (#{l(:field_private_notes)})" if journal.private_notes?
681 598
            pdf.RDMCell(190,5, title)
682
            pdf.Ln
599
            pdf.ln
683 600
            pdf.SetFontStyle('I',8)
684 601
            details_to_strings(journal.visible_details, true).each do |string|
685 602
              pdf.RDMMultiCell(190,5, "- " + string)
686 603
            end
687 604
            if journal.notes?
688
              pdf.Ln unless journal.details.empty?
605
              pdf.ln unless journal.details.empty?
689 606
              pdf.SetFontStyle('',8)
690
              pdf.RDMwriteHTMLCell(190,5,0,0,
607
              pdf.RDMwriteHTMLCell(190,5,'','',
691 608
                    journal.notes.to_s, issue.attachments, "")
692 609
            end
693
            pdf.Ln
610
            pdf.ln
694 611
          end
695 612
        end
696 613

  
697 614
        if issue.attachments.any?
698 615
          pdf.SetFontStyle('B',9)
699 616
          pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
700
          pdf.Ln
617
          pdf.ln
701 618
          for attachment in issue.attachments
702 619
            pdf.SetFontStyle('',8)
703 620
            pdf.RDMCell(80,5, attachment.filename)
704 621
            pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
705 622
            pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
706 623
            pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
707
            pdf.Ln
624
            pdf.ln
708 625
          end
709 626
        end
710
        pdf.Output
627
        pdf.output
711 628
      end
712 629

  
713 630
      # Returns a PDF string of a set of wiki pages
714 631
      def wiki_pages_to_pdf(pages, project)
715 632
        pdf = ITCPDF.new(current_language)
716
        pdf.SetTitle(project.name)
633
        pdf.set_title(project.name)
717 634
        pdf.alias_nb_pages
718 635
        pdf.footer_date = format_date(Date.today)
719
        pdf.AddPage
636
        pdf.add_page
720 637
        pdf.SetFontStyle('B',11)
721 638
        pdf.RDMMultiCell(190,5, project.name)
722
        pdf.Ln
639
        pdf.ln
723 640
        # Set resize image scale
724
        pdf.SetImageScale(1.6)
641
        pdf.set_image_scale(1.6)
725 642
        pdf.SetFontStyle('',9)
726 643
        write_page_hierarchy(pdf, pages.group_by(&:parent_id))
727
        pdf.Output
644
        pdf.output
728 645
      end
729 646

  
730 647
      # Returns a PDF string of a single wiki page
731 648
      def wiki_page_to_pdf(page, project)
732 649
        pdf = ITCPDF.new(current_language)
733
        pdf.SetTitle("#{project} - #{page.title}")
650
        pdf.set_title("#{project} - #{page.title}")
734 651
        pdf.alias_nb_pages
735 652
        pdf.footer_date = format_date(Date.today)
736
        pdf.AddPage
653
        pdf.add_page
737 654
        pdf.SetFontStyle('B',11)
738 655
        pdf.RDMMultiCell(190,5,
739 656
             "#{project} - #{page.title} - # #{page.content.version}")
740
        pdf.Ln
657
        pdf.ln
741 658
        # Set resize image scale
742
        pdf.SetImageScale(1.6)
659
        pdf.set_image_scale(1.6)
743 660
        pdf.SetFontStyle('',9)
744 661
        write_wiki_page(pdf, page)
745
        pdf.Output
662
        pdf.output
746 663
      end
747 664

  
748 665
      def write_page_hierarchy(pdf, pages, node=nil, level=0)
749 666
        if pages[node]
750 667
          pages[node].each do |page|
751 668
            if @new_page
752
              pdf.AddPage
669
              pdf.add_page
753 670
            else
754 671
              @new_page = true
755 672
            end
756
            pdf.Bookmark page.title, level
673
            pdf.bookmark page.title, level
757 674
            write_wiki_page(pdf, page)
758 675
            write_page_hierarchy(pdf, pages, page.id, level + 1) if pages[page.id]
759 676
          end
......
761 678
      end
762 679

  
763 680
      def write_wiki_page(pdf, page)
764
        pdf.RDMwriteHTMLCell(190,5,0,0,
681
        pdf.RDMwriteHTMLCell(190,5,'','',
765 682
              page.content.text.to_s, page.attachments, 0)
766 683
        if page.attachments.any?
767
          pdf.Ln
684
          pdf.ln(5)
768 685
          pdf.SetFontStyle('B',9)
769 686
          pdf.RDMCell(190,5, l(:label_attachment_plural), "B")
770
          pdf.Ln
687
          pdf.ln
771 688
          for attachment in page.attachments
772 689
            pdf.SetFontStyle('',8)
773 690
            pdf.RDMCell(80,5, attachment.filename)
774 691
            pdf.RDMCell(20,5, number_to_human_size(attachment.filesize),0,0,"R")
775 692
            pdf.RDMCell(25,5, format_date(attachment.created_on),0,0,"R")
776 693
            pdf.RDMCell(65,5, attachment.author.name,0,0,"R")
777
            pdf.Ln
694
            pdf.ln
778 695
          end
779 696
        end
780 697
      end
lib/redmine/helpers/gantt.rb (working copy)
856 856
      end
857 857

  
858 858
      def pdf_task(params, coords, options={})
859
        cell_height_ratio = params[:pdf].get_cell_height_ratio()
860
        params[:pdf].set_cell_height_ratio(0.1)
861

  
859 862
        height = options[:height] || 2
860 863
        # Renders the task bar, with progress and late
861 864
        if coords[:bar_start] && coords[:bar_end]
......
896 899
          params[:pdf].SetX(params[:subject_width] + (coords[:bar_end] || 0) + 5)
897 900
          params[:pdf].RDMCell(30, 2, options[:label])
898 901
        end
902

  
903
        params[:pdf].set_cell_height_ratio(cell_height_ratio)
899 904
      end
900 905

  
901 906
      def image_task(params, coords, options={})
(5-5/8)