Project

General

Profile

Patch #10464 » pdf.diff

Yuri Makarov, 2012-03-16 09:26

View differences:

pdf.rb Fri Mar 16 11:25:55 2012
144 144
        end
145 145
      end
146 146

  
147
	  # fetch row values
148
	  def fetch_row_values(issue, query, level)	
149
	    query.columns.collect do |column|
150
		  s = if column.is_a?(QueryCustomFieldColumn)
151
		    cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
152
		    show_value(cv)
153
		  else
154
		    value = issue.send(column.name)
155
		    if column.name == :subject
156
			  value = "  " * level + value
157
		    end
158
		    if value.is_a?(Date)
159
			  format_date(value)
160
		    elsif value.is_a?(Time)
161
			  format_time(value)
162
		    else
163
			  value
164
		    end
165
		  end
166
		  s.to_s
167
	    end
168
	  end
169

  
170
	  # calculate columns width
171
	  def calc_col_width(issues, query, table_width, pdf)
172
		  # calculate statistics
173
		  #  by captions
174
		  col_width_min = query.columns.map {|v| pdf.GetStringWidth(v.caption)}
175
		  col_width_max = Array.new(col_width_min)
176
		  col_width_avg = Array.new(col_width_min)
177
		  word_width_max = query.columns.map {|c| 
178
			n = 10
179
			c.caption.split.each {|w| 
180
			  x = pdf.GetStringWidth(w)
181
			  n = x if n < x
182
			}
183
			n
184
		  }
185

  
186
		  #  by properties of issues
187
		  k = 1
188
		  issue_list(issues) {|issue, level|
189
			k += 1
190
			values = fetch_row_values(issue, query, level)
191
		    values.each_with_index {|v,i| 
192
			  n = pdf.GetStringWidth(v.rstrip)
193
			  col_width_max[i] = n if col_width_max[i] < n
194
			  col_width_min[i] = n if col_width_min[i] > n
195
			  col_width_avg[i] += n
196
			  v.split.each {|w| 
197
				x = pdf.GetStringWidth(w); 
198
				word_width_max[i] = x if word_width_max[i] < x
199
			  }
200
			}
201
		  }
202
		  col_width_avg.map! {|x| x / k}
203
		  
204
		  # calculate columns width
205
          ratio = table_width / col_width_avg.inject(0) {|s,w| s += w}
206
          col_width = col_width_avg.map {|w| w * ratio}
207
		  
208
		  # correct max word width if too many columns
209
		  ratio = table_width / word_width_max.inject(0) {|s,w| s += w}
210
		  word_width_max.map! {|v| v * ratio} if ratio < 1
211
		  
212
		  # correct and lock width of some columns
213
		  done = 1
214
		  col_fix = []
215
		  col_width.each_with_index do |w,i| 
216
		    if w > col_width_max[i]
217
			  col_width[i] = col_width_max[i]
218
			  col_fix[i] = 1
219
			  done = 0
220
			elsif w < word_width_max[i]
221
			  col_width[i] = word_width_max[i]
222
			  col_fix[i] = 1
223
			  done = 0
224
			else
225
			  col_fix[i] = 0
226
			end
227
		  end
228

  
229
		  # iterate while need to correct and lock coluns width
230
		  while done == 0 
231
			# calculate free & locked columns width
232
		    done = 1
233
			fix_col_width = 0
234
			free_col_width = 0
235
			col_width.each_with_index do |w,i|
236
			  if col_fix[i] == 1
237
				fix_col_width += w
238
			  else
239
				free_col_width += w
240
			  end
241
			end
242
			
243
			# calculate column normalizing ratio
244
			if free_col_width == 0
245
			  ratio = table_width / col_width.inject(0) {|s,w| s += w}
246
			else
247
			  ratio = (table_width - fix_col_width) / free_col_width
248
			end
249

  
250
			# correct columns width
251
			col_width.each_with_index do |w,i| 
252
			  if col_fix[i] == 0
253
				col_width[i] = w * ratio
254
				
255
				# check if column width less then max word width
256
				if col_width[i] < word_width_max[i]
257
				  col_width[i] = word_width_max[i]
258
				  col_fix[i] = 1
259
				  done = 0
260
				end
261
			  end
262
			end
263
		  end 
264
		  
265
		  # calculate columns alignment
266
		  @col_align = col_width.map {|x| x < table_width / col_width.count ? 'C' : 'L'}
267
		  
268
		  col_width
269
	  end
270

  
271
	  def render_table_header(pdf, query, col_width, row_height, col_id_width, table_width)
272
        # headers
273
        pdf.SetFontStyle('B',8)
274
        pdf.SetFillColor(230, 230, 230)
275

  
276
        # render it background to find the max height used
277
        base_x = pdf.GetX
278
        base_y = pdf.GetY
279
        max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
280
        pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
281
        pdf.SetXY(base_x, base_y);
282

  
283
        # write the cells on page
284
        pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
285
        issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
286
        issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
287
        pdf.SetY(base_y + max_height);
288

  
289
        # rows
290
        pdf.SetFontStyle('',8)
291
        pdf.SetFillColor(255, 255, 255)
292
	  end
293
	  # ---
294
	  
147 295
      # Returns a PDF string of a list of issues
148 296
      def issues_to_pdf(issues, project, query)
149 297
        pdf = ITCPDF.new(current_language)
......
167 315
        table_width = page_width - right_margin - 10  # fixed left margin
168 316
        col_width = []
169 317
        unless query.columns.empty?
170
          col_width = query.columns.collect do |c|
171
            (c.name == :subject || (c.is_a?(QueryCustomFieldColumn) &&
172
              ['string', 'text'].include?(c.custom_field.field_format))) ? 4.0 : 1.0
173
          end
174
          ratio = (table_width - col_id_width) / col_width.inject(0) {|s,w| s += w}
175
          col_width = col_width.collect {|w| w * ratio}
318
		  col_width = calc_col_width(issues, query, table_width - col_id_width, pdf)
319
		  table_width = col_width.inject(0) {|s,v| s += v}
176 320
        end
177 321

  
178 322
        # title
......
180 324
        pdf.RDMCell(190,10, title)
181 325
        pdf.Ln
182 326

  
183
        # headers
184
        pdf.SetFontStyle('B',8)
185
        pdf.SetFillColor(230, 230, 230)
186

  
187
        # render it background to find the max height used
188
        base_x = pdf.GetX
189
        base_y = pdf.GetY
190
        max_height = issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
191
        pdf.Rect(base_x, base_y, table_width, max_height, 'FD');
192
        pdf.SetXY(base_x, base_y);
193

  
194
        # write the cells on page
195
        pdf.RDMCell(col_id_width, row_height, "#", "T", 0, 'C', 1)
196
        issues_to_pdf_write_cells(pdf, query.columns, col_width, row_height, true)
197
        issues_to_pdf_draw_borders(pdf, base_x, base_y, base_y + max_height, col_id_width, col_width)
198
        pdf.SetY(base_y + max_height);
199

  
200
        # rows
201
        pdf.SetFontStyle('',8)
202
        pdf.SetFillColor(255, 255, 255)
327
		render_table_header(pdf, query, col_width, row_height, col_id_width, table_width)
328
		
203 329
        previous_group = false
204 330
        issue_list(issues) do |issue, level|
205 331
          if query.grouped? &&
206 332
               (group = query.group_by_column.value(issue)) != previous_group
207
            pdf.SetFontStyle('B',9)
208
            pdf.RDMCell(277, row_height,
209
              (group.blank? ? 'None' : group.to_s) + " (#{query.issue_count_by_group[group]})",
333
            pdf.SetFontStyle('B',10)
334
            pdf.RDMCell(table_width + col_id_width, row_height * 2,
335
              (group.blank? ? '  None' : '  ' + group.to_s) + " (#{query.issue_count_by_group[group]})",
210 336
              1, 1, 'L')
211 337
            pdf.SetFontStyle('',8)
212 338
            previous_group = group
213 339
          end
214
          # fetch all the row values
215
          col_values = query.columns.collect do |column|
216
            s = if column.is_a?(QueryCustomFieldColumn)
217
              cv = issue.custom_values.detect {|v| v.custom_field_id == column.custom_field.id}
218
              show_value(cv)
219
            else
220
              value = issue.send(column.name)
221
              if column.name == :subject
222
                value = "  " * level + value
223
              end
224
              if value.is_a?(Date)
225
                format_date(value)
226
              elsif value.is_a?(Time)
227
                format_time(value)
228
              else
229
                value
230
              end
231
            end
232
            s.to_s
233
          end
340

  
341
          # fetch row values
342
		  col_values = fetch_row_values(issue, query, level)
234 343

  
235 344
          # render it off-page to find the max height used
236 345
          base_x = pdf.GetX
......
245 354
            pdf.AddPage("L")
246 355
            base_x = pdf.GetX
247 356
            base_y = pdf.GetY
357
			render_table_header(pdf, query, col_width, row_height, col_id_width, table_width)
248 358
          end
249 359

  
250 360
          # write the cells on page
......
264 374
      # Renders MultiCells and returns the maximum height used
265 375
      def issues_to_pdf_write_cells(pdf, col_values, col_widths,
266 376
                                    row_height, head=false)
267
        base_y = pdf.GetY
377
		@col_align ||= []
378
		base_y = pdf.GetY
268 379
        max_height = row_height
269 380
        col_values.each_with_index do |column, i|
270 381
          col_x = pdf.GetX
271 382
          if head == true
272
            pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'L', 1)
383
            pdf.RDMMultiCell(col_widths[i], row_height, column.caption, "T", 'C', 1)
273 384
          else
274
            pdf.RDMMultiCell(col_widths[i], row_height, column, "T", 'L', 1)
385
			@col_align[i] = 'L' if @col_align[i].nil?
386
            pdf.RDMMultiCell(col_widths[i], row_height, column, "T", @col_align[i], 1)
275 387
          end
276 388
          max_height = (pdf.GetY - base_y) if (pdf.GetY - base_y) > max_height
277 389
          pdf.SetXY(col_x + col_widths[i], base_y);
(1-1/10)